aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp/feat.c
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2008-11-05 02:55:49 -0500
committerDavid S. Miller <davem@davemloft.net>2008-11-05 02:55:49 -0500
commitac75773c2742d82cbcb078708df406e9017224b7 (patch)
tree7e7b1aa5131c4a61aabd9d86d7332eca98d66a89 /net/dccp/feat.c
parent61e6473efbd6087e1db3aaa93a5266c5bfd8aa99 (diff)
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>
Diffstat (limited to 'net/dccp/feat.c')
-rw-r--r--net/dccp/feat.c55
1 files changed, 55 insertions, 0 deletions
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
index 9a37b6ce3ac..069d8ffe4c6 100644
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -90,6 +90,20 @@ static u8 dccp_feat_type(u8 feat_num)
90 return dccp_feat_table[idx].reconciliation; 90 return dccp_feat_table[idx].reconciliation;
91} 91}
92 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
93static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val) 107static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
94{ 108{
95 if (unlikely(val == NULL)) 109 if (unlikely(val == NULL))
@@ -99,6 +113,28 @@ static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
99 memset(val, 0, sizeof(*val)); 113 memset(val, 0, sizeof(*val));
100} 114}
101 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
102static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry) 138static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
103{ 139{
104 if (entry != NULL) { 140 if (entry != NULL) {
@@ -133,6 +169,25 @@ void dccp_feat_list_purge(struct list_head *fn_list)
133} 169}
134EXPORT_SYMBOL_GPL(dccp_feat_list_purge); 170EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
135 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
136int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, 191int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
137 u8 *val, u8 len, gfp_t gfp) 192 u8 *val, u8 len, gfp_t gfp)
138{ 193{