diff options
-rw-r--r-- | net/dccp/dccp.h | 1 | ||||
-rw-r--r-- | net/dccp/feat.c | 25 | ||||
-rw-r--r-- | net/dccp/output.c | 13 |
3 files changed, 35 insertions, 4 deletions
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index 1881527bdcd7..e656dafb5d96 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h | |||
@@ -443,6 +443,7 @@ static inline int dccp_ack_pending(const struct sock *sk) | |||
443 | } | 443 | } |
444 | 444 | ||
445 | extern int dccp_feat_finalise_settings(struct dccp_sock *dp); | 445 | extern int dccp_feat_finalise_settings(struct dccp_sock *dp); |
446 | extern int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq); | ||
446 | extern void dccp_feat_list_purge(struct list_head *fn_list); | 447 | extern void dccp_feat_list_purge(struct list_head *fn_list); |
447 | 448 | ||
448 | extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb); | 449 | 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 ed9f50b1c34a..6852960bb0a9 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c | |||
@@ -601,6 +601,31 @@ int dccp_feat_finalise_settings(struct dccp_sock *dp) | |||
601 | return 0; | 601 | return 0; |
602 | } | 602 | } |
603 | 603 | ||
604 | /** | ||
605 | * dccp_feat_server_ccid_dependencies - Resolve CCID-dependent features | ||
606 | * It is the server which resolves the dependencies once the CCID has been | ||
607 | * fully negotiated. If no CCID has been negotiated, it uses the default CCID. | ||
608 | */ | ||
609 | int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq) | ||
610 | { | ||
611 | struct list_head *fn = &dreq->dreq_featneg; | ||
612 | struct dccp_feat_entry *entry; | ||
613 | u8 is_local, ccid; | ||
614 | |||
615 | for (is_local = 0; is_local <= 1; is_local++) { | ||
616 | entry = dccp_feat_list_lookup(fn, DCCPF_CCID, is_local); | ||
617 | |||
618 | if (entry != NULL && !entry->empty_confirm) | ||
619 | ccid = entry->val.sp.vec[0]; | ||
620 | else | ||
621 | ccid = dccp_feat_default_value(DCCPF_CCID); | ||
622 | |||
623 | if (dccp_feat_propagate_ccid(fn, ccid, is_local)) | ||
624 | return -1; | ||
625 | } | ||
626 | return 0; | ||
627 | } | ||
628 | |||
604 | static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr) | 629 | static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr) |
605 | { | 630 | { |
606 | struct dccp_sock *dp = dccp_sk(sk); | 631 | struct dccp_sock *dp = dccp_sk(sk); |
diff --git a/net/dccp/output.c b/net/dccp/output.c index dc96ecfbe6e8..19a93d5433a7 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c | |||
@@ -339,10 +339,12 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, | |||
339 | DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE; | 339 | DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE; |
340 | DCCP_SKB_CB(skb)->dccpd_seq = dreq->dreq_iss; | 340 | DCCP_SKB_CB(skb)->dccpd_seq = dreq->dreq_iss; |
341 | 341 | ||
342 | if (dccp_insert_options_rsk(dreq, skb)) { | 342 | /* Resolve feature dependencies resulting from choice of CCID */ |
343 | kfree_skb(skb); | 343 | if (dccp_feat_server_ccid_dependencies(dreq)) |
344 | return NULL; | 344 | goto response_failed; |
345 | } | 345 | |
346 | if (dccp_insert_options_rsk(dreq, skb)) | ||
347 | goto response_failed; | ||
346 | 348 | ||
347 | /* Build and checksum header */ | 349 | /* Build and checksum header */ |
348 | dh = dccp_zeroed_hdr(skb, dccp_header_size); | 350 | dh = dccp_zeroed_hdr(skb, dccp_header_size); |
@@ -363,6 +365,9 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, | |||
363 | inet_rsk(req)->acked = 1; | 365 | inet_rsk(req)->acked = 1; |
364 | DCCP_INC_STATS(DCCP_MIB_OUTSEGS); | 366 | DCCP_INC_STATS(DCCP_MIB_OUTSEGS); |
365 | return skb; | 367 | return skb; |
368 | response_failed: | ||
369 | kfree_skb(skb); | ||
370 | return NULL; | ||
366 | } | 371 | } |
367 | 372 | ||
368 | EXPORT_SYMBOL_GPL(dccp_make_response); | 373 | EXPORT_SYMBOL_GPL(dccp_make_response); |