diff options
author | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2008-11-05 02:55:49 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-11-05 02:55:49 -0500 |
commit | ac75773c2742d82cbcb078708df406e9017224b7 (patch) | |
tree | 7e7b1aa5131c4a61aabd9d86d7332eca98d66a89 | |
parent | 61e6473efbd6087e1db3aaa93a5266c5bfd8aa99 (diff) |
dccp: Per-socket initialisation of feature negotiation
This provides feature-negotiation initialisation for both DCCP sockets
and DCCP request_sockets, to support feature negotiation during
connection setup.
It also resolves a FIXME regarding the congestion control
initialisation.
Thanks to Wei Yongjun for help with the IPv6 side of this patch.
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>
-rw-r--r-- | include/linux/dccp.h | 4 | ||||
-rw-r--r-- | net/dccp/dccp.h | 3 | ||||
-rw-r--r-- | net/dccp/feat.c | 55 | ||||
-rw-r--r-- | net/dccp/feat.h | 1 | ||||
-rw-r--r-- | net/dccp/input.c | 2 | ||||
-rw-r--r-- | net/dccp/ipv4.c | 3 | ||||
-rw-r--r-- | net/dccp/ipv6.c | 3 | ||||
-rw-r--r-- | net/dccp/minisocks.c | 7 | ||||
-rw-r--r-- | net/dccp/proto.c | 1 |
9 files changed, 73 insertions, 6 deletions
diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 3978aff197d9..484b8a1fb023 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h | |||
@@ -412,6 +412,7 @@ extern void dccp_minisock_init(struct dccp_minisock *dmsk); | |||
412 | * @dreq_iss: initial sequence number sent on the Response (RFC 4340, 7.1) | 412 | * @dreq_iss: initial sequence number sent on the Response (RFC 4340, 7.1) |
413 | * @dreq_isr: initial sequence number received on the Request | 413 | * @dreq_isr: initial sequence number received on the Request |
414 | * @dreq_service: service code present on the Request (there is just one) | 414 | * @dreq_service: service code present on the Request (there is just one) |
415 | * @dreq_featneg: feature negotiation options for this connection | ||
415 | * The following two fields are analogous to the ones in dccp_sock: | 416 | * The following two fields are analogous to the ones in dccp_sock: |
416 | * @dreq_timestamp_echo: last received timestamp to echo (13.1) | 417 | * @dreq_timestamp_echo: last received timestamp to echo (13.1) |
417 | * @dreq_timestamp_echo: the time of receiving the last @dreq_timestamp_echo | 418 | * @dreq_timestamp_echo: the time of receiving the last @dreq_timestamp_echo |
@@ -421,6 +422,7 @@ struct dccp_request_sock { | |||
421 | __u64 dreq_iss; | 422 | __u64 dreq_iss; |
422 | __u64 dreq_isr; | 423 | __u64 dreq_isr; |
423 | __be32 dreq_service; | 424 | __be32 dreq_service; |
425 | struct list_head dreq_featneg; | ||
424 | __u32 dreq_timestamp_echo; | 426 | __u32 dreq_timestamp_echo; |
425 | __u32 dreq_timestamp_time; | 427 | __u32 dreq_timestamp_time; |
426 | }; | 428 | }; |
@@ -498,6 +500,7 @@ struct dccp_ackvec; | |||
498 | * @dccps_mss_cache - current value of MSS (path MTU minus header sizes) | 500 | * @dccps_mss_cache - current value of MSS (path MTU minus header sizes) |
499 | * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4) | 501 | * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4) |
500 | * @dccps_minisock - associated minisock (accessed via dccp_msk) | 502 | * @dccps_minisock - associated minisock (accessed via dccp_msk) |
503 | * @dccps_featneg - tracks feature-negotiation state (mostly during handshake) | ||
501 | * @dccps_hc_rx_ackvec - rx half connection ack vector | 504 | * @dccps_hc_rx_ackvec - rx half connection ack vector |
502 | * @dccps_hc_rx_ccid - CCID used for the receiver (or receiving half-connection) | 505 | * @dccps_hc_rx_ccid - CCID used for the receiver (or receiving half-connection) |
503 | * @dccps_hc_tx_ccid - CCID used for the sender (or sending half-connection) | 506 | * @dccps_hc_tx_ccid - CCID used for the sender (or sending half-connection) |
@@ -535,6 +538,7 @@ struct dccp_sock { | |||
535 | __u64 dccps_ndp_count:48; | 538 | __u64 dccps_ndp_count:48; |
536 | unsigned long dccps_rate_last; | 539 | unsigned long dccps_rate_last; |
537 | struct dccp_minisock dccps_minisock; | 540 | struct dccp_minisock dccps_minisock; |
541 | struct list_head dccps_featneg; | ||
538 | struct dccp_ackvec *dccps_hc_rx_ackvec; | 542 | struct dccp_ackvec *dccps_hc_rx_ackvec; |
539 | struct ccid *dccps_hc_rx_ccid; | 543 | struct ccid *dccps_hc_rx_ccid; |
540 | struct ccid *dccps_hc_tx_ccid; | 544 | struct ccid *dccps_hc_tx_ccid; |
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index d6fed595a3ff..dee4a90886d6 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h | |||
@@ -252,7 +252,8 @@ extern const char *dccp_state_name(const int state); | |||
252 | extern void dccp_set_state(struct sock *sk, const int state); | 252 | extern void dccp_set_state(struct sock *sk, const int state); |
253 | extern void dccp_done(struct sock *sk); | 253 | extern void dccp_done(struct sock *sk); |
254 | 254 | ||
255 | extern void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb); | 255 | extern int dccp_reqsk_init(struct request_sock *rq, struct dccp_sock const *dp, |
256 | struct sk_buff const *skb); | ||
256 | 257 | ||
257 | extern int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb); | 258 | extern int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb); |
258 | 259 | ||
diff --git a/net/dccp/feat.c b/net/dccp/feat.c index 9a37b6ce3aca..069d8ffe4c6f 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c | |||
@@ -90,6 +90,20 @@ static u8 dccp_feat_type(u8 feat_num) | |||
90 | return dccp_feat_table[idx].reconciliation; | 90 | return dccp_feat_table[idx].reconciliation; |
91 | } | 91 | } |
92 | 92 | ||
93 | /* copy constructor, fval must not already contain allocated memory */ | ||
94 | static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len) | ||
95 | { | ||
96 | fval->sp.len = len; | ||
97 | if (fval->sp.len > 0) { | ||
98 | fval->sp.vec = kmemdup(val, len, gfp_any()); | ||
99 | if (fval->sp.vec == NULL) { | ||
100 | fval->sp.len = 0; | ||
101 | return -ENOBUFS; | ||
102 | } | ||
103 | } | ||
104 | return 0; | ||
105 | } | ||
106 | |||
93 | static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val) | 107 | static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val) |
94 | { | 108 | { |
95 | if (unlikely(val == NULL)) | 109 | if (unlikely(val == NULL)) |
@@ -99,6 +113,28 @@ static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val) | |||
99 | memset(val, 0, sizeof(*val)); | 113 | memset(val, 0, sizeof(*val)); |
100 | } | 114 | } |
101 | 115 | ||
116 | static struct dccp_feat_entry * | ||
117 | dccp_feat_clone_entry(struct dccp_feat_entry const *original) | ||
118 | { | ||
119 | struct dccp_feat_entry *new; | ||
120 | u8 type = dccp_feat_type(original->feat_num); | ||
121 | |||
122 | if (type == FEAT_UNKNOWN) | ||
123 | return NULL; | ||
124 | |||
125 | new = kmemdup(original, sizeof(struct dccp_feat_entry), gfp_any()); | ||
126 | if (new == NULL) | ||
127 | return NULL; | ||
128 | |||
129 | if (type == FEAT_SP && dccp_feat_clone_sp_val(&new->val, | ||
130 | original->val.sp.vec, | ||
131 | original->val.sp.len)) { | ||
132 | kfree(new); | ||
133 | return NULL; | ||
134 | } | ||
135 | return new; | ||
136 | } | ||
137 | |||
102 | static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry) | 138 | static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry) |
103 | { | 139 | { |
104 | if (entry != NULL) { | 140 | if (entry != NULL) { |
@@ -133,6 +169,25 @@ void dccp_feat_list_purge(struct list_head *fn_list) | |||
133 | } | 169 | } |
134 | EXPORT_SYMBOL_GPL(dccp_feat_list_purge); | 170 | EXPORT_SYMBOL_GPL(dccp_feat_list_purge); |
135 | 171 | ||
172 | /* generate @to as full clone of @from - @to must not contain any nodes */ | ||
173 | int dccp_feat_clone_list(struct list_head const *from, struct list_head *to) | ||
174 | { | ||
175 | struct dccp_feat_entry *entry, *new; | ||
176 | |||
177 | INIT_LIST_HEAD(to); | ||
178 | list_for_each_entry(entry, from, node) { | ||
179 | new = dccp_feat_clone_entry(entry); | ||
180 | if (new == NULL) | ||
181 | goto cloning_failed; | ||
182 | list_add_tail(&new->node, to); | ||
183 | } | ||
184 | return 0; | ||
185 | |||
186 | cloning_failed: | ||
187 | dccp_feat_list_purge(to); | ||
188 | return -ENOMEM; | ||
189 | } | ||
190 | |||
136 | int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, | 191 | int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, |
137 | u8 *val, u8 len, gfp_t gfp) | 192 | u8 *val, u8 len, gfp_t gfp) |
138 | { | 193 | { |
diff --git a/net/dccp/feat.h b/net/dccp/feat.h index 56df82ceef09..f5e99b39712a 100644 --- a/net/dccp/feat.h +++ b/net/dccp/feat.h | |||
@@ -96,6 +96,7 @@ extern int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, | |||
96 | u8 *val, u8 len); | 96 | u8 *val, u8 len); |
97 | extern void dccp_feat_clean(struct dccp_minisock *dmsk); | 97 | extern void dccp_feat_clean(struct dccp_minisock *dmsk); |
98 | extern int dccp_feat_clone(struct sock *oldsk, struct sock *newsk); | 98 | extern int dccp_feat_clone(struct sock *oldsk, struct sock *newsk); |
99 | extern int dccp_feat_clone_list(struct list_head const *, struct list_head *); | ||
99 | extern int dccp_feat_init(struct dccp_minisock *dmsk); | 100 | extern int dccp_feat_init(struct dccp_minisock *dmsk); |
100 | 101 | ||
101 | #endif /* _DCCP_FEAT_H */ | 102 | #endif /* _DCCP_FEAT_H */ |
diff --git a/net/dccp/input.c b/net/dccp/input.c index 779d0ed9ae94..3070015edc75 100644 --- a/net/dccp/input.c +++ b/net/dccp/input.c | |||
@@ -590,8 +590,6 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, | |||
590 | if (inet_csk(sk)->icsk_af_ops->conn_request(sk, | 590 | if (inet_csk(sk)->icsk_af_ops->conn_request(sk, |
591 | skb) < 0) | 591 | skb) < 0) |
592 | return 1; | 592 | return 1; |
593 | |||
594 | /* FIXME: do congestion control initialization */ | ||
595 | goto discard; | 593 | goto discard; |
596 | } | 594 | } |
597 | if (dh->dccph_type == DCCP_PKT_RESET) | 595 | if (dh->dccph_type == DCCP_PKT_RESET) |
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 01e3e0206254..cbf522dfecc4 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
@@ -595,7 +595,8 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
595 | if (req == NULL) | 595 | if (req == NULL) |
596 | goto drop; | 596 | goto drop; |
597 | 597 | ||
598 | dccp_reqsk_init(req, skb); | 598 | if (dccp_reqsk_init(req, dccp_sk(sk), skb)) |
599 | goto drop_and_free; | ||
599 | 600 | ||
600 | dreq = dccp_rsk(req); | 601 | dreq = dccp_rsk(req); |
601 | if (dccp_parse_options(sk, dreq, skb)) | 602 | if (dccp_parse_options(sk, dreq, skb)) |
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index d4ce1224e008..4e172ccfd76c 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c | |||
@@ -426,7 +426,8 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
426 | if (req == NULL) | 426 | if (req == NULL) |
427 | goto drop; | 427 | goto drop; |
428 | 428 | ||
429 | dccp_reqsk_init(req, skb); | 429 | if (dccp_reqsk_init(req, dccp_sk(sk), skb)) |
430 | goto drop_and_free; | ||
430 | 431 | ||
431 | dreq = dccp_rsk(req); | 432 | dreq = dccp_rsk(req); |
432 | if (dccp_parse_options(sk, dreq, skb)) | 433 | if (dccp_parse_options(sk, dreq, skb)) |
diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index e6bf99e3e41a..afdacbb94d75 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c | |||
@@ -125,6 +125,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk, | |||
125 | newdp->dccps_timestamp_time = dreq->dreq_timestamp_time; | 125 | newdp->dccps_timestamp_time = dreq->dreq_timestamp_time; |
126 | newicsk->icsk_rto = DCCP_TIMEOUT_INIT; | 126 | newicsk->icsk_rto = DCCP_TIMEOUT_INIT; |
127 | 127 | ||
128 | INIT_LIST_HEAD(&newdp->dccps_featneg); | ||
128 | if (dccp_feat_clone(sk, newsk)) | 129 | if (dccp_feat_clone(sk, newsk)) |
129 | goto out_free; | 130 | goto out_free; |
130 | 131 | ||
@@ -304,7 +305,8 @@ void dccp_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, | |||
304 | 305 | ||
305 | EXPORT_SYMBOL_GPL(dccp_reqsk_send_ack); | 306 | EXPORT_SYMBOL_GPL(dccp_reqsk_send_ack); |
306 | 307 | ||
307 | void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb) | 308 | int dccp_reqsk_init(struct request_sock *req, |
309 | struct dccp_sock const *dp, struct sk_buff const *skb) | ||
308 | { | 310 | { |
309 | struct dccp_request_sock *dreq = dccp_rsk(req); | 311 | struct dccp_request_sock *dreq = dccp_rsk(req); |
310 | 312 | ||
@@ -313,6 +315,9 @@ void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb) | |||
313 | inet_rsk(req)->acked = 0; | 315 | inet_rsk(req)->acked = 0; |
314 | req->rcv_wnd = sysctl_dccp_feat_sequence_window; | 316 | req->rcv_wnd = sysctl_dccp_feat_sequence_window; |
315 | dreq->dreq_timestamp_echo = 0; | 317 | dreq->dreq_timestamp_echo = 0; |
318 | |||
319 | /* inherit feature negotiation options from listening socket */ | ||
320 | return dccp_feat_clone_list(&dp->dccps_featneg, &dreq->dreq_featneg); | ||
316 | } | 321 | } |
317 | 322 | ||
318 | EXPORT_SYMBOL_GPL(dccp_reqsk_init); | 323 | EXPORT_SYMBOL_GPL(dccp_reqsk_init); |
diff --git a/net/dccp/proto.c b/net/dccp/proto.c index d0bd34819761..1cdf4ae99605 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c | |||
@@ -193,6 +193,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized) | |||
193 | 193 | ||
194 | dccp_init_xmit_timers(sk); | 194 | dccp_init_xmit_timers(sk); |
195 | 195 | ||
196 | INIT_LIST_HEAD(&dp->dccps_featneg); | ||
196 | /* | 197 | /* |
197 | * FIXME: We're hardcoding the CCID, and doing this at this point makes | 198 | * FIXME: We're hardcoding the CCID, and doing this at this point makes |
198 | * the listening (master) sock get CCID control blocks, which is not | 199 | * the listening (master) sock get CCID control blocks, which is not |