Skip to content

Commit e8ef967

Browse files
Gerrit Renkerdavem330
authored andcommitted
dccp: Registration routines for changing feature values
Two registration routines, for SP and NN features, are provided by this patch, replacing a previous routine which was used for both feature types. These are internal-only routines and therefore start with `__feat_register'. It further exports the known limits of Sequence Window and Ack Ratio as symbolic constants. Signed-off-by: Gerrit Renker <[email protected]> Acked-by: Ian McDonald <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent f74e91b commit e8ef967

File tree

4 files changed

+197
-28
lines changed

4 files changed

+197
-28
lines changed

net/dccp/ccids/ccid2.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
/*
2626
* This implementation should follow RFC 4341
2727
*/
28-
28+
#include "../feat.h"
2929
#include "../ccid.h"
3030
#include "../dccp.h"
3131
#include "ccid2.h"
@@ -147,8 +147,8 @@ static void ccid2_change_l_ack_ratio(struct sock *sk, u32 val)
147147
DCCP_WARN("Limiting Ack Ratio (%u) to %u\n", val, max_ratio);
148148
val = max_ratio;
149149
}
150-
if (val > 0xFFFF) /* RFC 4340, 11.3 */
151-
val = 0xFFFF;
150+
if (val > DCCPF_ACK_RATIO_MAX)
151+
val = DCCPF_ACK_RATIO_MAX;
152152

153153
if (val == dp->dccps_l_ack_ratio)
154154
return;

net/dccp/feat.c

Lines changed: 169 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,18 @@ static u8 dccp_feat_type(u8 feat_num)
9292
return dccp_feat_table[idx].reconciliation;
9393
}
9494

95+
static int dccp_feat_default_value(u8 feat_num)
96+
{
97+
int idx = dccp_feat_index(feat_num);
98+
/*
99+
* There are no default values for unknown features, so encountering a
100+
* negative index here indicates a serious problem somewhere else.
101+
*/
102+
DCCP_BUG_ON(idx < 0);
103+
104+
return idx < 0 ? 0 : dccp_feat_table[idx].default_value;
105+
}
106+
95107
/* copy constructor, fval must not already contain allocated memory */
96108
static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
97109
{
@@ -155,6 +167,63 @@ static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
155167
* - list is sorted in increasing order of feature number (faster lookup)
156168
*/
157169

170+
/**
171+
* dccp_feat_entry_new - Central list update routine (called by all others)
172+
* @head: list to add to
173+
* @feat: feature number
174+
* @local: whether the local (1) or remote feature with number @feat is meant
175+
* This is the only constructor and serves to ensure the above invariants.
176+
*/
177+
static struct dccp_feat_entry *
178+
dccp_feat_entry_new(struct list_head *head, u8 feat, bool local)
179+
{
180+
struct dccp_feat_entry *entry;
181+
182+
list_for_each_entry(entry, head, node)
183+
if (entry->feat_num == feat && entry->is_local == local) {
184+
dccp_feat_val_destructor(entry->feat_num, &entry->val);
185+
return entry;
186+
} else if (entry->feat_num > feat) {
187+
head = &entry->node;
188+
break;
189+
}
190+
191+
entry = kmalloc(sizeof(*entry), gfp_any());
192+
if (entry != NULL) {
193+
entry->feat_num = feat;
194+
entry->is_local = local;
195+
list_add_tail(&entry->node, head);
196+
}
197+
return entry;
198+
}
199+
200+
/**
201+
* dccp_feat_push_change - Add/overwrite a Change option in the list
202+
* @fn_list: feature-negotiation list to update
203+
* @feat: one of %dccp_feature_numbers
204+
* @local: whether local (1) or remote (0) @feat_num is meant
205+
* @needs_mandatory: whether to use Mandatory feature negotiation options
206+
* @fval: pointer to NN/SP value to be inserted (will be copied)
207+
*/
208+
static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
209+
u8 mandatory, dccp_feat_val *fval)
210+
{
211+
struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
212+
213+
if (new == NULL)
214+
return -ENOMEM;
215+
216+
new->feat_num = feat;
217+
new->is_local = local;
218+
new->state = FEAT_INITIALISING;
219+
new->needs_confirm = 0;
220+
new->empty_confirm = 0;
221+
new->val = *fval;
222+
new->needs_mandatory = mandatory;
223+
224+
return 0;
225+
}
226+
158227
static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
159228
{
160229
list_del(&entry->node);
@@ -190,6 +259,95 @@ int dccp_feat_clone_list(struct list_head const *from, struct list_head *to)
190259
return -ENOMEM;
191260
}
192261

262+
static u8 dccp_feat_is_valid_nn_val(u8 feat_num, u64 val)
263+
{
264+
switch (feat_num) {
265+
case DCCPF_ACK_RATIO:
266+
return val <= DCCPF_ACK_RATIO_MAX;
267+
case DCCPF_SEQUENCE_WINDOW:
268+
return val >= DCCPF_SEQ_WMIN && val <= DCCPF_SEQ_WMAX;
269+
}
270+
return 0; /* feature unknown - so we can't tell */
271+
}
272+
273+
/* check that SP values are within the ranges defined in RFC 4340 */
274+
static u8 dccp_feat_is_valid_sp_val(u8 feat_num, u8 val)
275+
{
276+
switch (feat_num) {
277+
case DCCPF_CCID:
278+
return val == DCCPC_CCID2 || val == DCCPC_CCID3;
279+
/* Type-check Boolean feature values: */
280+
case DCCPF_SHORT_SEQNOS:
281+
case DCCPF_ECN_INCAPABLE:
282+
case DCCPF_SEND_ACK_VECTOR:
283+
case DCCPF_SEND_NDP_COUNT:
284+
case DCCPF_DATA_CHECKSUM:
285+
case DCCPF_SEND_LEV_RATE:
286+
return val < 2;
287+
case DCCPF_MIN_CSUM_COVER:
288+
return val < 16;
289+
}
290+
return 0; /* feature unknown */
291+
}
292+
293+
static u8 dccp_feat_sp_list_ok(u8 feat_num, u8 const *sp_list, u8 sp_len)
294+
{
295+
if (sp_list == NULL || sp_len < 1)
296+
return 0;
297+
while (sp_len--)
298+
if (!dccp_feat_is_valid_sp_val(feat_num, *sp_list++))
299+
return 0;
300+
return 1;
301+
}
302+
303+
/**
304+
* __feat_register_nn - Register new NN value on socket
305+
* @fn: feature-negotiation list to register with
306+
* @feat: an NN feature from %dccp_feature_numbers
307+
* @mandatory: use Mandatory option if 1
308+
* @nn_val: value to register (restricted to 4 bytes)
309+
* Note that NN features are local by definition (RFC 4340, 6.3.2).
310+
*/
311+
static int __feat_register_nn(struct list_head *fn, u8 feat,
312+
u8 mandatory, u64 nn_val)
313+
{
314+
dccp_feat_val fval = { .nn = nn_val };
315+
316+
if (dccp_feat_type(feat) != FEAT_NN ||
317+
!dccp_feat_is_valid_nn_val(feat, nn_val))
318+
return -EINVAL;
319+
320+
/* Don't bother with default values, they will be activated anyway. */
321+
if (nn_val - (u64)dccp_feat_default_value(feat) == 0)
322+
return 0;
323+
324+
return dccp_feat_push_change(fn, feat, 1, mandatory, &fval);
325+
}
326+
327+
/**
328+
* __feat_register_sp - Register new SP value/list on socket
329+
* @fn: feature-negotiation list to register with
330+
* @feat: an SP feature from %dccp_feature_numbers
331+
* @is_local: whether the local (1) or the remote (0) @feat is meant
332+
* @mandatory: use Mandatory option if 1
333+
* @sp_val: SP value followed by optional preference list
334+
* @sp_len: length of @sp_val in bytes
335+
*/
336+
static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local,
337+
u8 mandatory, u8 const *sp_val, u8 sp_len)
338+
{
339+
dccp_feat_val fval;
340+
341+
if (dccp_feat_type(feat) != FEAT_SP ||
342+
!dccp_feat_sp_list_ok(feat, sp_val, sp_len))
343+
return -EINVAL;
344+
345+
if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len))
346+
return -ENOMEM;
347+
348+
return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval);
349+
}
350+
193351
int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
194352
u8 *val, u8 len, gfp_t gfp)
195353
{
@@ -726,42 +884,30 @@ int dccp_feat_clone(struct sock *oldsk, struct sock *newsk)
726884

727885
EXPORT_SYMBOL_GPL(dccp_feat_clone);
728886

729-
static int __dccp_feat_init(struct dccp_minisock *dmsk, u8 type, u8 feat,
730-
u8 *val, u8 len)
731-
{
732-
int rc = -ENOMEM;
733-
u8 *copy = kmemdup(val, len, GFP_KERNEL);
734-
735-
if (copy != NULL) {
736-
rc = dccp_feat_change(dmsk, type, feat, copy, len, GFP_KERNEL);
737-
if (rc)
738-
kfree(copy);
739-
}
740-
return rc;
741-
}
742-
743-
int dccp_feat_init(struct dccp_minisock *dmsk)
887+
int dccp_feat_init(struct sock *sk)
744888
{
889+
struct dccp_sock *dp = dccp_sk(sk);
890+
struct dccp_minisock *dmsk = dccp_msk(sk);
745891
int rc;
746892

747-
INIT_LIST_HEAD(&dmsk->dccpms_pending);
748-
INIT_LIST_HEAD(&dmsk->dccpms_conf);
893+
INIT_LIST_HEAD(&dmsk->dccpms_pending); /* XXX no longer used */
894+
INIT_LIST_HEAD(&dmsk->dccpms_conf); /* XXX no longer used */
749895

750896
/* CCID L */
751-
rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_CCID,
752-
&dmsk->dccpms_tx_ccid, 1);
897+
rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 1, 0,
898+
&dmsk->dccpms_tx_ccid, 1);
753899
if (rc)
754900
goto out;
755901

756902
/* CCID R */
757-
rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_R, DCCPF_CCID,
758-
&dmsk->dccpms_rx_ccid, 1);
903+
rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 0, 0,
904+
&dmsk->dccpms_rx_ccid, 1);
759905
if (rc)
760906
goto out;
761907

762908
/* Ack ratio */
763-
rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_ACK_RATIO,
764-
&dmsk->dccpms_ack_ratio, 1);
909+
rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
910+
dmsk->dccpms_ack_ratio);
765911
out:
766912
return rc;
767913
}

net/dccp/feat.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,15 @@
1414
#include <linux/types.h>
1515
#include "dccp.h"
1616

17+
/*
18+
* Known limit values
19+
*/
20+
/* Ack Ratio takes 2-byte integer values (11.3) */
21+
#define DCCPF_ACK_RATIO_MAX 0xFFFF
22+
/* Wmin=32 and Wmax=2^46-1 from 7.5.2 */
23+
#define DCCPF_SEQ_WMIN 32
24+
#define DCCPF_SEQ_WMAX 0x3FFFFFFFFFFFull
25+
1726
enum dccp_feat_type {
1827
FEAT_AT_RX = 1, /* located at RX side of half-connection */
1928
FEAT_AT_TX = 2, /* located at TX side of half-connection */
@@ -75,6 +84,20 @@ static inline u8 dccp_feat_genopt(struct dccp_feat_entry *entry)
7584
return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R;
7685
}
7786

87+
/**
88+
* struct ccid_dependency - Track changes resulting from choosing a CCID
89+
* @dependent_feat: one of %dccp_feature_numbers
90+
* @is_local: local (1) or remote (0) @dependent_feat
91+
* @is_mandatory: whether presence of @dependent_feat is mission-critical or not
92+
* @val: corresponding default value for @dependent_feat (u8 is sufficient here)
93+
*/
94+
struct ccid_dependency {
95+
u8 dependent_feat;
96+
bool is_local:1,
97+
is_mandatory:1;
98+
u8 val;
99+
};
100+
78101
#ifdef CONFIG_IP_DCCP_DEBUG
79102
extern const char *dccp_feat_typename(const u8 type);
80103
extern const char *dccp_feat_name(const u8 feat);
@@ -97,6 +120,6 @@ extern int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
97120
extern void dccp_feat_clean(struct dccp_minisock *dmsk);
98121
extern int dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
99122
extern int dccp_feat_clone_list(struct list_head const *, struct list_head *);
100-
extern int dccp_feat_init(struct dccp_minisock *dmsk);
123+
extern int dccp_feat_init(struct sock *sk);
101124

102125
#endif /* _DCCP_FEAT_H */

net/dccp/proto.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
202202
* setsockopt(CCIDs-I-want/accept). -acme
203203
*/
204204
if (likely(ctl_sock_initialized)) {
205-
int rc = dccp_feat_init(dmsk);
205+
int rc = dccp_feat_init(sk);
206206

207207
if (rc)
208208
return rc;

0 commit comments

Comments
 (0)