aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2008-11-17 01:49:52 -0500
committerDavid S. Miller <davem@davemloft.net>2008-11-17 01:49:52 -0500
commit0c1168398ecbfacbb27203b281bde20ec9f78017 (patch)
tree3298379e950bba174b46e53102f265829340fa6d /net
parent3f2c31d90327f21d76d296af34aa4ca547932ff4 (diff)
dccp: Mechanism to resolve CCID dependencies
This adds a hook to resolve features whose value depends on the choice of CCID. It is done at the server since it can only be done after the CCID values have been negotiated; i.e. the client will add its CCID preference list on the Change options sent in the Request, which will be reconciled with the local preference list of the server. The concept is documented on http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/feature_negotiation/\ implementation_notes.html#ccid_dependencies Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/dccp/dccp.h1
-rw-r--r--net/dccp/feat.c37
-rw-r--r--net/dccp/output.c13
3 files changed, 47 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
445extern int dccp_feat_finalise_settings(struct dccp_sock *dp); 445extern int dccp_feat_finalise_settings(struct dccp_sock *dp);
446extern int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq);
446extern void dccp_feat_list_purge(struct list_head *fn_list); 447extern void dccp_feat_list_purge(struct list_head *fn_list);
447 448
448extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb); 449extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
index 4c4144147325..4f86a48723f6 100644
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -166,6 +166,18 @@ static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
166 * - SP values are always freshly allocated 166 * - SP values are always freshly allocated
167 * - list is sorted in increasing order of feature number (faster lookup) 167 * - list is sorted in increasing order of feature number (faster lookup)
168 */ 168 */
169static struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list,
170 u8 feat_num, bool is_local)
171{
172 struct dccp_feat_entry *entry;
173
174 list_for_each_entry(entry, fn_list, node)
175 if (entry->feat_num == feat_num && entry->is_local == is_local)
176 return entry;
177 else if (entry->feat_num > feat_num)
178 break;
179 return NULL;
180}
169 181
170/** 182/**
171 * dccp_feat_entry_new - Central list update routine (called by all others) 183 * dccp_feat_entry_new - Central list update routine (called by all others)
@@ -560,6 +572,31 @@ int dccp_feat_finalise_settings(struct dccp_sock *dp)
560 return 0; 572 return 0;
561} 573}
562 574
575/**
576 * dccp_feat_server_ccid_dependencies - Resolve CCID-dependent features
577 * It is the server which resolves the dependencies once the CCID has been
578 * fully negotiated. If no CCID has been negotiated, it uses the default CCID.
579 */
580int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq)
581{
582 struct list_head *fn = &dreq->dreq_featneg;
583 struct dccp_feat_entry *entry;
584 u8 is_local, ccid;
585
586 for (is_local = 0; is_local <= 1; is_local++) {
587 entry = dccp_feat_list_lookup(fn, DCCPF_CCID, is_local);
588
589 if (entry != NULL && !entry->empty_confirm)
590 ccid = entry->val.sp.vec[0];
591 else
592 ccid = dccp_feat_default_value(DCCPF_CCID);
593
594 if (dccp_feat_propagate_ccid(fn, ccid, is_local))
595 return -1;
596 }
597 return 0;
598}
599
563static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr) 600static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr)
564{ 601{
565 struct dccp_sock *dp = dccp_sk(sk); 602 struct dccp_sock *dp = dccp_sk(sk);
diff --git a/net/dccp/output.c b/net/dccp/output.c
index 92f3f6f2ef51..fea30cdc0bee 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;
368response_failed:
369 kfree_skb(skb);
370 return NULL;
366} 371}
367 372
368EXPORT_SYMBOL_GPL(dccp_make_response); 373EXPORT_SYMBOL_GPL(dccp_make_response);