aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/dccp/dccp.h2
-rw-r--r--net/dccp/feat.c65
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
444extern int dccp_feat_finalise_settings(struct dccp_sock *dp); 444extern int dccp_feat_finalise_settings(struct dccp_sock *dp);
445extern int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq); 445extern int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq);
446extern int dccp_feat_insert_opts(struct dccp_sock*, struct dccp_request_sock*,
447 struct sk_buff *skb);
446extern void dccp_feat_list_purge(struct list_head *fn_list); 448extern void dccp_feat_list_purge(struct list_head *fn_list);
447 449
448extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb); 450extern 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 */
280static 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
275static u8 dccp_feat_is_valid_nn_val(u8 feat_num, u64 val) 289static 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 */
336int 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