diff options
-rw-r--r-- | net/dccp/dccp.h | 2 | ||||
-rw-r--r-- | net/dccp/feat.c | 65 |
2 files changed, 67 insertions, 0 deletions
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index 33a1127270c1..4ed7c5936bcf 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h | |||
@@ -443,6 +443,8 @@ static inline int dccp_ack_pending(const struct sock *sk) | |||
443 | 443 | ||
444 | extern int dccp_feat_finalise_settings(struct dccp_sock *dp); | 444 | extern int dccp_feat_finalise_settings(struct dccp_sock *dp); |
445 | extern int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq); | 445 | extern int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq); |
446 | extern int dccp_feat_insert_opts(struct dccp_sock*, struct dccp_request_sock*, | ||
447 | struct sk_buff *skb); | ||
446 | extern void dccp_feat_list_purge(struct list_head *fn_list); | 448 | extern void dccp_feat_list_purge(struct list_head *fn_list); |
447 | 449 | ||
448 | extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb); | 450 | extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb); |
diff --git a/net/dccp/feat.c b/net/dccp/feat.c index 2c2216f64b1b..d90caa7198c3 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c | |||
@@ -272,6 +272,20 @@ cloning_failed: | |||
272 | return -ENOMEM; | 272 | return -ENOMEM; |
273 | } | 273 | } |
274 | 274 | ||
275 | /** | ||
276 | * dccp_feat_valid_nn_length - Enforce length constraints on NN options | ||
277 | * Length is between 0 and %DCCP_OPTVAL_MAXLEN. Used for outgoing packets only, | ||
278 | * incoming options are accepted as long as their values are valid. | ||
279 | */ | ||
280 | static u8 dccp_feat_valid_nn_length(u8 feat_num) | ||
281 | { | ||
282 | if (feat_num == DCCPF_ACK_RATIO) /* RFC 4340, 11.3 and 6.6.8 */ | ||
283 | return 2; | ||
284 | if (feat_num == DCCPF_SEQUENCE_WINDOW) /* RFC 4340, 7.5.2 and 6.5 */ | ||
285 | return 6; | ||
286 | return 0; | ||
287 | } | ||
288 | |||
275 | static u8 dccp_feat_is_valid_nn_val(u8 feat_num, u64 val) | 289 | static u8 dccp_feat_is_valid_nn_val(u8 feat_num, u64 val) |
276 | { | 290 | { |
277 | switch (feat_num) { | 291 | switch (feat_num) { |
@@ -314,6 +328,57 @@ static u8 dccp_feat_sp_list_ok(u8 feat_num, u8 const *sp_list, u8 sp_len) | |||
314 | } | 328 | } |
315 | 329 | ||
316 | /** | 330 | /** |
331 | * dccp_feat_insert_opts - Generate FN options from current list state | ||
332 | * @skb: next sk_buff to be sent to the peer | ||
333 | * @dp: for client during handshake and general negotiation | ||
334 | * @dreq: used by the server only (all Changes/Confirms in LISTEN/RESPOND) | ||
335 | */ | ||
336 | int dccp_feat_insert_opts(struct dccp_sock *dp, struct dccp_request_sock *dreq, | ||
337 | struct sk_buff *skb) | ||
338 | { | ||
339 | struct list_head *fn = dreq ? &dreq->dreq_featneg : &dp->dccps_featneg; | ||
340 | struct dccp_feat_entry *pos, *next; | ||
341 | u8 opt, type, len, *ptr, nn_in_nbo[DCCP_OPTVAL_MAXLEN]; | ||
342 | bool rpt; | ||
343 | |||
344 | /* put entries into @skb in the order they appear in the list */ | ||
345 | list_for_each_entry_safe_reverse(pos, next, fn, node) { | ||
346 | opt = dccp_feat_genopt(pos); | ||
347 | type = dccp_feat_type(pos->feat_num); | ||
348 | rpt = false; | ||
349 | |||
350 | if (pos->empty_confirm) { | ||
351 | len = 0; | ||
352 | ptr = NULL; | ||
353 | } else { | ||
354 | if (type == FEAT_SP) { | ||
355 | len = pos->val.sp.len; | ||
356 | ptr = pos->val.sp.vec; | ||
357 | rpt = pos->needs_confirm; | ||
358 | } else if (type == FEAT_NN) { | ||
359 | len = dccp_feat_valid_nn_length(pos->feat_num); | ||
360 | ptr = nn_in_nbo; | ||
361 | dccp_encode_value_var(pos->val.nn, ptr, len); | ||
362 | } else { | ||
363 | DCCP_BUG("unknown feature %u", pos->feat_num); | ||
364 | return -1; | ||
365 | } | ||
366 | } | ||
367 | |||
368 | if (dccp_insert_fn_opt(skb, opt, pos->feat_num, ptr, len, rpt)) | ||
369 | return -1; | ||
370 | if (pos->needs_mandatory && dccp_insert_option_mandatory(skb)) | ||
371 | return -1; | ||
372 | /* | ||
373 | * Enter CHANGING after transmitting the Change option (6.6.2). | ||
374 | */ | ||
375 | if (pos->state == FEAT_INITIALISING) | ||
376 | pos->state = FEAT_CHANGING; | ||
377 | } | ||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | /** | ||
317 | * __feat_register_nn - Register new NN value on socket | 382 | * __feat_register_nn - Register new NN value on socket |
318 | * @fn: feature-negotiation list to register with | 383 | * @fn: feature-negotiation list to register with |
319 | * @feat: an NN feature from %dccp_feature_numbers | 384 | * @feat: an NN feature from %dccp_feature_numbers |