aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2008-09-04 01:30:19 -0400
committerGerrit Renker <gerrit@erg.abdn.ac.uk>2008-09-04 01:45:26 -0400
commit3001fc0569651f2d0c3b45adc991351471b0c382 (patch)
treeec89ae53bf5e345a971ee92fec8816677e46fc69 /net
parentb4eec206370b7154dc354dc30f0a3f02ea8468b2 (diff)
dccp: List management for new feature negotiation
This adds list fields and list management functions for the new feature negotiation implementation. The new code is kept in parallel to the old code, until removed at the end of the patch set. Thanks to Arnaldo for suggestions to improve the code. Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Diffstat (limited to 'net')
-rw-r--r--net/dccp/feat.c129
1 files changed, 129 insertions, 0 deletions
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
index d7468f70544d..2ec2cd117699 100644
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -150,6 +150,135 @@ static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
150 } 150 }
151} 151}
152 152
153/*
154 * List management functions
155 *
156 * Feature negotiation lists rely on and maintain the following invariants:
157 * - each feat_num in the list is known, i.e. we know its type and default value
158 * - each feat_num/is_local combination is unique (old entries are overwritten)
159 * - SP values are always freshly allocated
160 * - list is sorted in increasing order of feature number (faster lookup)
161 */
162static struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list,
163 u8 feat_num, bool is_local)
164{
165 struct dccp_feat_entry *entry;
166
167 list_for_each_entry(entry, fn_list, node)
168 if (entry->feat_num == feat_num && entry->is_local == is_local)
169 return entry;
170 else if (entry->feat_num > feat_num)
171 break;
172 return NULL;
173}
174
175/**
176 * dccp_feat_entry_new - Central list update routine (called by all others)
177 * @head: list to add to
178 * @feat: feature number
179 * @local: whether the local (1) or remote feature with number @feat is meant
180 * This is the only constructor and serves to ensure the above invariants.
181 */
182static struct dccp_feat_entry *
183 dccp_feat_entry_new(struct list_head *head, u8 feat, bool local)
184{
185 struct dccp_feat_entry *entry;
186
187 list_for_each_entry(entry, head, node)
188 if (entry->feat_num == feat && entry->is_local == local) {
189 dccp_feat_val_destructor(entry->feat_num, &entry->val);
190 return entry;
191 } else if (entry->feat_num > feat) {
192 head = &entry->node;
193 break;
194 }
195
196 entry = kmalloc(sizeof(*entry), gfp_any());
197 if (entry != NULL) {
198 entry->feat_num = feat;
199 entry->is_local = local;
200 list_add_tail(&entry->node, head);
201 }
202 return entry;
203}
204
205/**
206 * dccp_feat_push_change - Add/overwrite a Change option in the list
207 * @fn_list: feature-negotiation list to update
208 * @feat: one of %dccp_feature_numbers
209 * @local: whether local (1) or remote (0) @feat_num is meant
210 * @needs_mandatory: whether to use Mandatory feature negotiation options
211 * @fval: pointer to NN/SP value to be inserted (will be copied)
212 */
213static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
214 u8 mandatory, dccp_feat_val *fval)
215{
216 struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
217
218 if (new == NULL)
219 return -ENOMEM;
220
221 new->feat_num = feat;
222 new->is_local = local;
223 new->state = FEAT_INITIALISING;
224 new->needs_confirm = 0;
225 new->empty_confirm = 0;
226 new->val = *fval;
227 new->needs_mandatory = mandatory;
228
229 return 0;
230}
231
232/**
233 * dccp_feat_push_confirm - Add a Confirm entry to the FN list
234 * @fn_list: feature-negotiation list to add to
235 * @feat: one of %dccp_feature_numbers
236 * @local: whether local (1) or remote (0) @feat_num is being confirmed
237 * @fval: pointer to NN/SP value to be inserted or NULL
238 * Returns 0 on success, a Reset code for further processing otherwise.
239 */
240static int dccp_feat_push_confirm(struct list_head *fn_list, u8 feat, u8 local,
241 dccp_feat_val *fval)
242{
243 struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
244
245 if (new == NULL)
246 return DCCP_RESET_CODE_TOO_BUSY;
247
248 new->feat_num = feat;
249 new->is_local = local;
250 new->state = FEAT_STABLE; /* transition in 6.6.2 */
251 new->needs_confirm = 1;
252 new->empty_confirm = (fval == NULL);
253 new->val.nn = 0; /* zeroes the whole structure */
254 if (!new->empty_confirm)
255 new->val = *fval;
256 new->needs_mandatory = 0;
257
258 return 0;
259}
260
261static int dccp_push_empty_confirm(struct list_head *fn_list, u8 feat, u8 local)
262{
263 return dccp_feat_push_confirm(fn_list, feat, local, NULL);
264}
265
266static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
267{
268 list_del(&entry->node);
269 dccp_feat_entry_destructor(entry);
270}
271
272void dccp_feat_list_purge(struct list_head *fn_list)
273{
274 struct dccp_feat_entry *entry, *next;
275
276 list_for_each_entry_safe(entry, next, fn_list, node)
277 dccp_feat_entry_destructor(entry);
278 INIT_LIST_HEAD(fn_list);
279}
280EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
281
153int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, 282int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
154 u8 *val, u8 len, gfp_t gfp) 283 u8 *val, u8 len, gfp_t gfp)
155{ 284{