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 031ce350d3c1..2e2a6f229eaf 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 44b10afd3fb6..da686464462d 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c | |||
@@ -300,6 +300,20 @@ cloning_failed: | |||
300 | return -ENOMEM; | 300 | return -ENOMEM; |
301 | } | 301 | } |
302 | 302 | ||
303 | /** | ||
304 | * dccp_feat_valid_nn_length - Enforce length constraints on NN options | ||
305 | * Length is between 0 and %DCCP_OPTVAL_MAXLEN. Used for outgoing packets only, | ||
306 | * incoming options are accepted as long as their values are valid. | ||
307 | */ | ||
308 | static u8 dccp_feat_valid_nn_length(u8 feat_num) | ||
309 | { | ||
310 | if (feat_num == DCCPF_ACK_RATIO) /* RFC 4340, 11.3 and 6.6.8 */ | ||
311 | return 2; | ||
312 | if (feat_num == DCCPF_SEQUENCE_WINDOW) /* RFC 4340, 7.5.2 and 6.5 */ | ||
313 | return 6; | ||
314 | return 0; | ||
315 | } | ||
316 | |||
303 | static u8 dccp_feat_is_valid_nn_val(u8 feat_num, u64 val) | 317 | static u8 dccp_feat_is_valid_nn_val(u8 feat_num, u64 val) |
304 | { | 318 | { |
305 | switch (feat_num) { | 319 | switch (feat_num) { |
@@ -342,6 +356,57 @@ static u8 dccp_feat_sp_list_ok(u8 feat_num, u8 const *sp_list, u8 sp_len) | |||
342 | } | 356 | } |
343 | 357 | ||
344 | /** | 358 | /** |
359 | * dccp_feat_insert_opts - Generate FN options from current list state | ||
360 | * @skb: next sk_buff to be sent to the peer | ||
361 | * @dp: for client during handshake and general negotiation | ||
362 | * @dreq: used by the server only (all Changes/Confirms in LISTEN/RESPOND) | ||
363 | */ | ||
364 | int dccp_feat_insert_opts(struct dccp_sock *dp, struct dccp_request_sock *dreq, | ||
365 | struct sk_buff *skb) | ||
366 | { | ||
367 | struct list_head *fn = dreq ? &dreq->dreq_featneg : &dp->dccps_featneg; | ||
368 | struct dccp_feat_entry *pos, *next; | ||
369 | u8 opt, type, len, *ptr, nn_in_nbo[DCCP_OPTVAL_MAXLEN]; | ||
370 | bool rpt; | ||
371 | |||
372 | /* put entries into @skb in the order they appear in the list */ | ||
373 | list_for_each_entry_safe_reverse(pos, next, fn, node) { | ||
374 | opt = dccp_feat_genopt(pos); | ||
375 | type = dccp_feat_type(pos->feat_num); | ||
376 | rpt = false; | ||
377 | |||
378 | if (pos->empty_confirm) { | ||
379 | len = 0; | ||
380 | ptr = NULL; | ||
381 | } else { | ||
382 | if (type == FEAT_SP) { | ||
383 | len = pos->val.sp.len; | ||
384 | ptr = pos->val.sp.vec; | ||
385 | rpt = pos->needs_confirm; | ||
386 | } else if (type == FEAT_NN) { | ||
387 | len = dccp_feat_valid_nn_length(pos->feat_num); | ||
388 | ptr = nn_in_nbo; | ||
389 | dccp_encode_value_var(pos->val.nn, ptr, len); | ||
390 | } else { | ||
391 | DCCP_BUG("unknown feature %u", pos->feat_num); | ||
392 | return -1; | ||
393 | } | ||
394 | } | ||
395 | |||
396 | if (dccp_insert_fn_opt(skb, opt, pos->feat_num, ptr, len, rpt)) | ||
397 | return -1; | ||
398 | if (pos->needs_mandatory && dccp_insert_option_mandatory(skb)) | ||
399 | return -1; | ||
400 | /* | ||
401 | * Enter CHANGING after transmitting the Change option (6.6.2). | ||
402 | */ | ||
403 | if (pos->state == FEAT_INITIALISING) | ||
404 | pos->state = FEAT_CHANGING; | ||
405 | } | ||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | /** | ||
345 | * __feat_register_nn - Register new NN value on socket | 410 | * __feat_register_nn - Register new NN value on socket |
346 | * @fn: feature-negotiation list to register with | 411 | * @fn: feature-negotiation list to register with |
347 | * @feat: an NN feature from %dccp_feature_numbers | 412 | * @feat: an NN feature from %dccp_feature_numbers |