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:
Gerrit Renker
2008-11-04 23:55:49 -08:00
committed by David S. Miller
parent 61e6473efb
commit ac75773c27
9 changed files with 73 additions and 6 deletions

View File

@@ -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)
{