dccp: Per-socket initialisation of feature negotiation
This provides feature-negotiation initialisation for both DCCP sockets and DCCP request_sockets, to support feature negotiation during connection setup. It also resolves a FIXME regarding the congestion control initialisation. Thanks to Wei Yongjun for help with the IPv6 side of this patch. 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>
This commit is contained in:
committed by
David S. Miller
parent
61e6473efb
commit
ac75773c27
@@ -90,6 +90,20 @@ static u8 dccp_feat_type(u8 feat_num)
|
||||
return dccp_feat_table[idx].reconciliation;
|
||||
}
|
||||
|
||||
/* copy constructor, fval must not already contain allocated memory */
|
||||
static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
|
||||
{
|
||||
fval->sp.len = len;
|
||||
if (fval->sp.len > 0) {
|
||||
fval->sp.vec = kmemdup(val, len, gfp_any());
|
||||
if (fval->sp.vec == NULL) {
|
||||
fval->sp.len = 0;
|
||||
return -ENOBUFS;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
|
||||
{
|
||||
if (unlikely(val == NULL))
|
||||
@@ -99,6 +113,28 @@ static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
|
||||
memset(val, 0, sizeof(*val));
|
||||
}
|
||||
|
||||
static struct dccp_feat_entry *
|
||||
dccp_feat_clone_entry(struct dccp_feat_entry const *original)
|
||||
{
|
||||
struct dccp_feat_entry *new;
|
||||
u8 type = dccp_feat_type(original->feat_num);
|
||||
|
||||
if (type == FEAT_UNKNOWN)
|
||||
return NULL;
|
||||
|
||||
new = kmemdup(original, sizeof(struct dccp_feat_entry), gfp_any());
|
||||
if (new == NULL)
|
||||
return NULL;
|
||||
|
||||
if (type == FEAT_SP && dccp_feat_clone_sp_val(&new->val,
|
||||
original->val.sp.vec,
|
||||
original->val.sp.len)) {
|
||||
kfree(new);
|
||||
return NULL;
|
||||
}
|
||||
return new;
|
||||
}
|
||||
|
||||
static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
|
||||
{
|
||||
if (entry != NULL) {
|
||||
@@ -133,6 +169,25 @@ void dccp_feat_list_purge(struct list_head *fn_list)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
|
||||
|
||||
/* generate @to as full clone of @from - @to must not contain any nodes */
|
||||
int dccp_feat_clone_list(struct list_head const *from, struct list_head *to)
|
||||
{
|
||||
struct dccp_feat_entry *entry, *new;
|
||||
|
||||
INIT_LIST_HEAD(to);
|
||||
list_for_each_entry(entry, from, node) {
|
||||
new = dccp_feat_clone_entry(entry);
|
||||
if (new == NULL)
|
||||
goto cloning_failed;
|
||||
list_add_tail(&new->node, to);
|
||||
}
|
||||
return 0;
|
||||
|
||||
cloning_failed:
|
||||
dccp_feat_list_purge(to);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
|
||||
u8 *val, u8 len, gfp_t gfp)
|
||||
{
|
||||
|
Reference in New Issue
Block a user