diff options
Diffstat (limited to 'net/dccp/options.c')
-rw-r--r-- | net/dccp/options.c | 291 |
1 files changed, 209 insertions, 82 deletions
diff --git a/net/dccp/options.c b/net/dccp/options.c index 0a76426c9aea..e9feb2a0c770 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c | |||
@@ -21,19 +21,23 @@ | |||
21 | #include "ackvec.h" | 21 | #include "ackvec.h" |
22 | #include "ccid.h" | 22 | #include "ccid.h" |
23 | #include "dccp.h" | 23 | #include "dccp.h" |
24 | #include "feat.h" | ||
24 | 25 | ||
25 | /* stores the default values for new connection. may be changed with sysctl */ | 26 | int dccp_feat_default_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW; |
26 | static const struct dccp_options dccpo_default_values = { | 27 | int dccp_feat_default_rx_ccid = DCCPF_INITIAL_CCID; |
27 | .dccpo_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW, | 28 | int dccp_feat_default_tx_ccid = DCCPF_INITIAL_CCID; |
28 | .dccpo_rx_ccid = DCCPF_INITIAL_CCID, | 29 | int dccp_feat_default_ack_ratio = DCCPF_INITIAL_ACK_RATIO; |
29 | .dccpo_tx_ccid = DCCPF_INITIAL_CCID, | 30 | int dccp_feat_default_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR; |
30 | .dccpo_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR, | 31 | int dccp_feat_default_send_ndp_count = DCCPF_INITIAL_SEND_NDP_COUNT; |
31 | .dccpo_send_ndp_count = DCCPF_INITIAL_SEND_NDP_COUNT, | ||
32 | }; | ||
33 | 32 | ||
34 | void dccp_options_init(struct dccp_options *dccpo) | 33 | void dccp_minisock_init(struct dccp_minisock *dmsk) |
35 | { | 34 | { |
36 | memcpy(dccpo, &dccpo_default_values, sizeof(*dccpo)); | 35 | dmsk->dccpms_sequence_window = dccp_feat_default_sequence_window; |
36 | dmsk->dccpms_rx_ccid = dccp_feat_default_rx_ccid; | ||
37 | dmsk->dccpms_tx_ccid = dccp_feat_default_tx_ccid; | ||
38 | dmsk->dccpms_ack_ratio = dccp_feat_default_ack_ratio; | ||
39 | dmsk->dccpms_send_ack_vector = dccp_feat_default_send_ack_vector; | ||
40 | dmsk->dccpms_send_ndp_count = dccp_feat_default_send_ndp_count; | ||
37 | } | 41 | } |
38 | 42 | ||
39 | static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len) | 43 | static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len) |
@@ -69,9 +73,12 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) | |||
69 | unsigned char opt, len; | 73 | unsigned char opt, len; |
70 | unsigned char *value; | 74 | unsigned char *value; |
71 | u32 elapsed_time; | 75 | u32 elapsed_time; |
76 | int rc; | ||
77 | int mandatory = 0; | ||
72 | 78 | ||
73 | memset(opt_recv, 0, sizeof(*opt_recv)); | 79 | memset(opt_recv, 0, sizeof(*opt_recv)); |
74 | 80 | ||
81 | opt = len = 0; | ||
75 | while (opt_ptr != opt_end) { | 82 | while (opt_ptr != opt_end) { |
76 | opt = *opt_ptr++; | 83 | opt = *opt_ptr++; |
77 | len = 0; | 84 | len = 0; |
@@ -100,6 +107,12 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) | |||
100 | switch (opt) { | 107 | switch (opt) { |
101 | case DCCPO_PADDING: | 108 | case DCCPO_PADDING: |
102 | break; | 109 | break; |
110 | case DCCPO_MANDATORY: | ||
111 | if (mandatory) | ||
112 | goto out_invalid_option; | ||
113 | if (pkt_type != DCCP_PKT_DATA) | ||
114 | mandatory = 1; | ||
115 | break; | ||
103 | case DCCPO_NDP_COUNT: | 116 | case DCCPO_NDP_COUNT: |
104 | if (len > 3) | 117 | if (len > 3) |
105 | goto out_invalid_option; | 118 | goto out_invalid_option; |
@@ -108,12 +121,37 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) | |||
108 | dccp_pr_debug("%sNDP count=%d\n", debug_prefix, | 121 | dccp_pr_debug("%sNDP count=%d\n", debug_prefix, |
109 | opt_recv->dccpor_ndp); | 122 | opt_recv->dccpor_ndp); |
110 | break; | 123 | break; |
124 | case DCCPO_CHANGE_L: | ||
125 | /* fall through */ | ||
126 | case DCCPO_CHANGE_R: | ||
127 | if (len < 2) | ||
128 | goto out_invalid_option; | ||
129 | rc = dccp_feat_change_recv(sk, opt, *value, value + 1, | ||
130 | len - 1); | ||
131 | /* | ||
132 | * When there is a change error, change_recv is | ||
133 | * responsible for dealing with it. i.e. reply with an | ||
134 | * empty confirm. | ||
135 | * If the change was mandatory, then we need to die. | ||
136 | */ | ||
137 | if (rc && mandatory) | ||
138 | goto out_invalid_option; | ||
139 | break; | ||
140 | case DCCPO_CONFIRM_L: | ||
141 | /* fall through */ | ||
142 | case DCCPO_CONFIRM_R: | ||
143 | if (len < 2) | ||
144 | goto out_invalid_option; | ||
145 | if (dccp_feat_confirm_recv(sk, opt, *value, | ||
146 | value + 1, len - 1)) | ||
147 | goto out_invalid_option; | ||
148 | break; | ||
111 | case DCCPO_ACK_VECTOR_0: | 149 | case DCCPO_ACK_VECTOR_0: |
112 | case DCCPO_ACK_VECTOR_1: | 150 | case DCCPO_ACK_VECTOR_1: |
113 | if (pkt_type == DCCP_PKT_DATA) | 151 | if (pkt_type == DCCP_PKT_DATA) |
114 | continue; | 152 | break; |
115 | 153 | ||
116 | if (dp->dccps_options.dccpo_send_ack_vector && | 154 | if (dccp_msk(sk)->dccpms_send_ack_vector && |
117 | dccp_ackvec_parse(sk, skb, opt, value, len)) | 155 | dccp_ackvec_parse(sk, skb, opt, value, len)) |
118 | goto out_invalid_option; | 156 | goto out_invalid_option; |
119 | break; | 157 | break; |
@@ -121,7 +159,7 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) | |||
121 | if (len != 4) | 159 | if (len != 4) |
122 | goto out_invalid_option; | 160 | goto out_invalid_option; |
123 | 161 | ||
124 | opt_recv->dccpor_timestamp = ntohl(*(u32 *)value); | 162 | opt_recv->dccpor_timestamp = ntohl(*(__be32 *)value); |
125 | 163 | ||
126 | dp->dccps_timestamp_echo = opt_recv->dccpor_timestamp; | 164 | dp->dccps_timestamp_echo = opt_recv->dccpor_timestamp; |
127 | dccp_timestamp(sk, &dp->dccps_timestamp_time); | 165 | dccp_timestamp(sk, &dp->dccps_timestamp_time); |
@@ -135,7 +173,7 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) | |||
135 | if (len != 4 && len != 6 && len != 8) | 173 | if (len != 4 && len != 6 && len != 8) |
136 | goto out_invalid_option; | 174 | goto out_invalid_option; |
137 | 175 | ||
138 | opt_recv->dccpor_timestamp_echo = ntohl(*(u32 *)value); | 176 | opt_recv->dccpor_timestamp_echo = ntohl(*(__be32 *)value); |
139 | 177 | ||
140 | dccp_pr_debug("%sTIMESTAMP_ECHO=%u, len=%d, ackno=%llu, ", | 178 | dccp_pr_debug("%sTIMESTAMP_ECHO=%u, len=%d, ackno=%llu, ", |
141 | debug_prefix, | 179 | debug_prefix, |
@@ -149,9 +187,9 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) | |||
149 | break; | 187 | break; |
150 | 188 | ||
151 | if (len == 6) | 189 | if (len == 6) |
152 | elapsed_time = ntohs(*(u16 *)(value + 4)); | 190 | elapsed_time = ntohs(*(__be16 *)(value + 4)); |
153 | else | 191 | else |
154 | elapsed_time = ntohl(*(u32 *)(value + 4)); | 192 | elapsed_time = ntohl(*(__be32 *)(value + 4)); |
155 | 193 | ||
156 | /* Give precedence to the biggest ELAPSED_TIME */ | 194 | /* Give precedence to the biggest ELAPSED_TIME */ |
157 | if (elapsed_time > opt_recv->dccpor_elapsed_time) | 195 | if (elapsed_time > opt_recv->dccpor_elapsed_time) |
@@ -165,9 +203,9 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) | |||
165 | continue; | 203 | continue; |
166 | 204 | ||
167 | if (len == 2) | 205 | if (len == 2) |
168 | elapsed_time = ntohs(*(u16 *)value); | 206 | elapsed_time = ntohs(*(__be16 *)value); |
169 | else | 207 | else |
170 | elapsed_time = ntohl(*(u32 *)value); | 208 | elapsed_time = ntohl(*(__be32 *)value); |
171 | 209 | ||
172 | if (elapsed_time > opt_recv->dccpor_elapsed_time) | 210 | if (elapsed_time > opt_recv->dccpor_elapsed_time) |
173 | opt_recv->dccpor_elapsed_time = elapsed_time; | 211 | opt_recv->dccpor_elapsed_time = elapsed_time; |
@@ -208,8 +246,15 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) | |||
208 | sk, opt, len); | 246 | sk, opt, len); |
209 | break; | 247 | break; |
210 | } | 248 | } |
249 | |||
250 | if (opt != DCCPO_MANDATORY) | ||
251 | mandatory = 0; | ||
211 | } | 252 | } |
212 | 253 | ||
254 | /* mandatory was the last byte in option list -> reset connection */ | ||
255 | if (mandatory) | ||
256 | goto out_invalid_option; | ||
257 | |||
213 | return 0; | 258 | return 0; |
214 | 259 | ||
215 | out_invalid_option: | 260 | out_invalid_option: |
@@ -219,6 +264,8 @@ out_invalid_option: | |||
219 | return -1; | 264 | return -1; |
220 | } | 265 | } |
221 | 266 | ||
267 | EXPORT_SYMBOL_GPL(dccp_parse_options); | ||
268 | |||
222 | static void dccp_encode_value_var(const u32 value, unsigned char *to, | 269 | static void dccp_encode_value_var(const u32 value, unsigned char *to, |
223 | const unsigned int len) | 270 | const unsigned int len) |
224 | { | 271 | { |
@@ -237,17 +284,14 @@ static inline int dccp_ndp_len(const int ndp) | |||
237 | return likely(ndp <= 0xFF) ? 1 : ndp <= 0xFFFF ? 2 : 3; | 284 | return likely(ndp <= 0xFF) ? 1 : ndp <= 0xFFFF ? 2 : 3; |
238 | } | 285 | } |
239 | 286 | ||
240 | void dccp_insert_option(struct sock *sk, struct sk_buff *skb, | 287 | int dccp_insert_option(struct sock *sk, struct sk_buff *skb, |
241 | const unsigned char option, | 288 | const unsigned char option, |
242 | const void *value, const unsigned char len) | 289 | const void *value, const unsigned char len) |
243 | { | 290 | { |
244 | unsigned char *to; | 291 | unsigned char *to; |
245 | 292 | ||
246 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 2 > DCCP_MAX_OPT_LEN) { | 293 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 2 > DCCP_MAX_OPT_LEN) |
247 | LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to insert " | 294 | return -1; |
248 | "%d option!\n", option); | ||
249 | return; | ||
250 | } | ||
251 | 295 | ||
252 | DCCP_SKB_CB(skb)->dccpd_opt_len += len + 2; | 296 | DCCP_SKB_CB(skb)->dccpd_opt_len += len + 2; |
253 | 297 | ||
@@ -256,11 +300,12 @@ void dccp_insert_option(struct sock *sk, struct sk_buff *skb, | |||
256 | *to++ = len + 2; | 300 | *to++ = len + 2; |
257 | 301 | ||
258 | memcpy(to, value, len); | 302 | memcpy(to, value, len); |
303 | return 0; | ||
259 | } | 304 | } |
260 | 305 | ||
261 | EXPORT_SYMBOL_GPL(dccp_insert_option); | 306 | EXPORT_SYMBOL_GPL(dccp_insert_option); |
262 | 307 | ||
263 | static void dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb) | 308 | static int dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb) |
264 | { | 309 | { |
265 | struct dccp_sock *dp = dccp_sk(sk); | 310 | struct dccp_sock *dp = dccp_sk(sk); |
266 | int ndp = dp->dccps_ndp_count; | 311 | int ndp = dp->dccps_ndp_count; |
@@ -276,7 +321,7 @@ static void dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb) | |||
276 | const int len = ndp_len + 2; | 321 | const int len = ndp_len + 2; |
277 | 322 | ||
278 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) | 323 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) |
279 | return; | 324 | return -1; |
280 | 325 | ||
281 | DCCP_SKB_CB(skb)->dccpd_opt_len += len; | 326 | DCCP_SKB_CB(skb)->dccpd_opt_len += len; |
282 | 327 | ||
@@ -285,6 +330,8 @@ static void dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb) | |||
285 | *ptr++ = len; | 330 | *ptr++ = len; |
286 | dccp_encode_value_var(ndp, ptr, ndp_len); | 331 | dccp_encode_value_var(ndp, ptr, ndp_len); |
287 | } | 332 | } |
333 | |||
334 | return 0; | ||
288 | } | 335 | } |
289 | 336 | ||
290 | static inline int dccp_elapsed_time_len(const u32 elapsed_time) | 337 | static inline int dccp_elapsed_time_len(const u32 elapsed_time) |
@@ -292,27 +339,18 @@ static inline int dccp_elapsed_time_len(const u32 elapsed_time) | |||
292 | return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4; | 339 | return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4; |
293 | } | 340 | } |
294 | 341 | ||
295 | void dccp_insert_option_elapsed_time(struct sock *sk, | 342 | int dccp_insert_option_elapsed_time(struct sock *sk, struct sk_buff *skb, |
296 | struct sk_buff *skb, | 343 | u32 elapsed_time) |
297 | u32 elapsed_time) | ||
298 | { | 344 | { |
299 | #ifdef CONFIG_IP_DCCP_DEBUG | ||
300 | struct dccp_sock *dp = dccp_sk(sk); | ||
301 | const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? | ||
302 | "CLIENT TX opt: " : "server TX opt: "; | ||
303 | #endif | ||
304 | const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time); | 345 | const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time); |
305 | const int len = 2 + elapsed_time_len; | 346 | const int len = 2 + elapsed_time_len; |
306 | unsigned char *to; | 347 | unsigned char *to; |
307 | 348 | ||
308 | if (elapsed_time_len == 0) | 349 | if (elapsed_time_len == 0) |
309 | return; | 350 | return 0; |
310 | 351 | ||
311 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) { | 352 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) |
312 | LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to " | 353 | return -1; |
313 | "insert elapsed time!\n"); | ||
314 | return; | ||
315 | } | ||
316 | 354 | ||
317 | DCCP_SKB_CB(skb)->dccpd_opt_len += len; | 355 | DCCP_SKB_CB(skb)->dccpd_opt_len += len; |
318 | 356 | ||
@@ -321,17 +359,14 @@ void dccp_insert_option_elapsed_time(struct sock *sk, | |||
321 | *to++ = len; | 359 | *to++ = len; |
322 | 360 | ||
323 | if (elapsed_time_len == 2) { | 361 | if (elapsed_time_len == 2) { |
324 | const u16 var16 = htons((u16)elapsed_time); | 362 | const __be16 var16 = htons((u16)elapsed_time); |
325 | memcpy(to, &var16, 2); | 363 | memcpy(to, &var16, 2); |
326 | } else { | 364 | } else { |
327 | const u32 var32 = htonl(elapsed_time); | 365 | const __be32 var32 = htonl(elapsed_time); |
328 | memcpy(to, &var32, 4); | 366 | memcpy(to, &var32, 4); |
329 | } | 367 | } |
330 | 368 | ||
331 | dccp_pr_debug("%sELAPSED_TIME=%u, len=%d, seqno=%llu\n", | 369 | return 0; |
332 | debug_prefix, elapsed_time, | ||
333 | len, | ||
334 | (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq); | ||
335 | } | 370 | } |
336 | 371 | ||
337 | EXPORT_SYMBOL_GPL(dccp_insert_option_elapsed_time); | 372 | EXPORT_SYMBOL_GPL(dccp_insert_option_elapsed_time); |
@@ -352,32 +387,27 @@ void dccp_timestamp(const struct sock *sk, struct timeval *tv) | |||
352 | 387 | ||
353 | EXPORT_SYMBOL_GPL(dccp_timestamp); | 388 | EXPORT_SYMBOL_GPL(dccp_timestamp); |
354 | 389 | ||
355 | void dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb) | 390 | int dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb) |
356 | { | 391 | { |
357 | struct timeval tv; | 392 | struct timeval tv; |
358 | u32 now; | 393 | __be32 now; |
359 | 394 | ||
360 | dccp_timestamp(sk, &tv); | 395 | dccp_timestamp(sk, &tv); |
361 | now = timeval_usecs(&tv) / 10; | 396 | now = htonl(timeval_usecs(&tv) / 10); |
362 | /* yes this will overflow but that is the point as we want a | 397 | /* yes this will overflow but that is the point as we want a |
363 | * 10 usec 32 bit timer which mean it wraps every 11.9 hours */ | 398 | * 10 usec 32 bit timer which mean it wraps every 11.9 hours */ |
364 | 399 | ||
365 | now = htonl(now); | 400 | return dccp_insert_option(sk, skb, DCCPO_TIMESTAMP, &now, sizeof(now)); |
366 | dccp_insert_option(sk, skb, DCCPO_TIMESTAMP, &now, sizeof(now)); | ||
367 | } | 401 | } |
368 | 402 | ||
369 | EXPORT_SYMBOL_GPL(dccp_insert_option_timestamp); | 403 | EXPORT_SYMBOL_GPL(dccp_insert_option_timestamp); |
370 | 404 | ||
371 | static void dccp_insert_option_timestamp_echo(struct sock *sk, | 405 | static int dccp_insert_option_timestamp_echo(struct sock *sk, |
372 | struct sk_buff *skb) | 406 | struct sk_buff *skb) |
373 | { | 407 | { |
374 | struct dccp_sock *dp = dccp_sk(sk); | 408 | struct dccp_sock *dp = dccp_sk(sk); |
375 | #ifdef CONFIG_IP_DCCP_DEBUG | ||
376 | const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? | ||
377 | "CLIENT TX opt: " : "server TX opt: "; | ||
378 | #endif | ||
379 | struct timeval now; | 409 | struct timeval now; |
380 | u32 tstamp_echo; | 410 | __be32 tstamp_echo; |
381 | u32 elapsed_time; | 411 | u32 elapsed_time; |
382 | int len, elapsed_time_len; | 412 | int len, elapsed_time_len; |
383 | unsigned char *to; | 413 | unsigned char *to; |
@@ -387,11 +417,8 @@ static void dccp_insert_option_timestamp_echo(struct sock *sk, | |||
387 | elapsed_time_len = dccp_elapsed_time_len(elapsed_time); | 417 | elapsed_time_len = dccp_elapsed_time_len(elapsed_time); |
388 | len = 6 + elapsed_time_len; | 418 | len = 6 + elapsed_time_len; |
389 | 419 | ||
390 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) { | 420 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) |
391 | LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to insert " | 421 | return -1; |
392 | "timestamp echo!\n"); | ||
393 | return; | ||
394 | } | ||
395 | 422 | ||
396 | DCCP_SKB_CB(skb)->dccpd_opt_len += len; | 423 | DCCP_SKB_CB(skb)->dccpd_opt_len += len; |
397 | 424 | ||
@@ -402,51 +429,149 @@ static void dccp_insert_option_timestamp_echo(struct sock *sk, | |||
402 | tstamp_echo = htonl(dp->dccps_timestamp_echo); | 429 | tstamp_echo = htonl(dp->dccps_timestamp_echo); |
403 | memcpy(to, &tstamp_echo, 4); | 430 | memcpy(to, &tstamp_echo, 4); |
404 | to += 4; | 431 | to += 4; |
405 | 432 | ||
406 | if (elapsed_time_len == 2) { | 433 | if (elapsed_time_len == 2) { |
407 | const u16 var16 = htons((u16)elapsed_time); | 434 | const __be16 var16 = htons((u16)elapsed_time); |
408 | memcpy(to, &var16, 2); | 435 | memcpy(to, &var16, 2); |
409 | } else if (elapsed_time_len == 4) { | 436 | } else if (elapsed_time_len == 4) { |
410 | const u32 var32 = htonl(elapsed_time); | 437 | const __be32 var32 = htonl(elapsed_time); |
411 | memcpy(to, &var32, 4); | 438 | memcpy(to, &var32, 4); |
412 | } | 439 | } |
413 | 440 | ||
414 | dccp_pr_debug("%sTIMESTAMP_ECHO=%u, len=%d, seqno=%llu\n", | ||
415 | debug_prefix, dp->dccps_timestamp_echo, | ||
416 | len, | ||
417 | (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq); | ||
418 | |||
419 | dp->dccps_timestamp_echo = 0; | 441 | dp->dccps_timestamp_echo = 0; |
420 | dp->dccps_timestamp_time.tv_sec = 0; | 442 | dp->dccps_timestamp_time.tv_sec = 0; |
421 | dp->dccps_timestamp_time.tv_usec = 0; | 443 | dp->dccps_timestamp_time.tv_usec = 0; |
444 | return 0; | ||
422 | } | 445 | } |
423 | 446 | ||
424 | void dccp_insert_options(struct sock *sk, struct sk_buff *skb) | 447 | static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat, |
448 | u8 *val, u8 len) | ||
449 | { | ||
450 | u8 *to; | ||
451 | |||
452 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 3 > DCCP_MAX_OPT_LEN) { | ||
453 | LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small" | ||
454 | " to insert feature %d option!\n", feat); | ||
455 | return -1; | ||
456 | } | ||
457 | |||
458 | DCCP_SKB_CB(skb)->dccpd_opt_len += len + 3; | ||
459 | |||
460 | to = skb_push(skb, len + 3); | ||
461 | *to++ = type; | ||
462 | *to++ = len + 3; | ||
463 | *to++ = feat; | ||
464 | |||
465 | if (len) | ||
466 | memcpy(to, val, len); | ||
467 | dccp_pr_debug("option %d feat %d len %d\n", type, feat, len); | ||
468 | |||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb) | ||
425 | { | 473 | { |
426 | struct dccp_sock *dp = dccp_sk(sk); | 474 | struct dccp_sock *dp = dccp_sk(sk); |
475 | struct dccp_minisock *dmsk = dccp_msk(sk); | ||
476 | struct dccp_opt_pend *opt, *next; | ||
477 | int change = 0; | ||
478 | |||
479 | /* confirm any options [NN opts] */ | ||
480 | list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) { | ||
481 | dccp_insert_feat_opt(skb, opt->dccpop_type, | ||
482 | opt->dccpop_feat, opt->dccpop_val, | ||
483 | opt->dccpop_len); | ||
484 | /* fear empty confirms */ | ||
485 | if (opt->dccpop_val) | ||
486 | kfree(opt->dccpop_val); | ||
487 | kfree(opt); | ||
488 | } | ||
489 | INIT_LIST_HEAD(&dmsk->dccpms_conf); | ||
490 | |||
491 | /* see which features we need to send */ | ||
492 | list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { | ||
493 | /* see if we need to send any confirm */ | ||
494 | if (opt->dccpop_sc) { | ||
495 | dccp_insert_feat_opt(skb, opt->dccpop_type + 1, | ||
496 | opt->dccpop_feat, | ||
497 | opt->dccpop_sc->dccpoc_val, | ||
498 | opt->dccpop_sc->dccpoc_len); | ||
499 | |||
500 | BUG_ON(!opt->dccpop_sc->dccpoc_val); | ||
501 | kfree(opt->dccpop_sc->dccpoc_val); | ||
502 | kfree(opt->dccpop_sc); | ||
503 | opt->dccpop_sc = NULL; | ||
504 | } | ||
505 | |||
506 | /* any option not confirmed, re-send it */ | ||
507 | if (!opt->dccpop_conf) { | ||
508 | dccp_insert_feat_opt(skb, opt->dccpop_type, | ||
509 | opt->dccpop_feat, opt->dccpop_val, | ||
510 | opt->dccpop_len); | ||
511 | change++; | ||
512 | } | ||
513 | } | ||
514 | |||
515 | /* Retransmit timer. | ||
516 | * If this is the master listening sock, we don't set a timer on it. It | ||
517 | * should be fine because if the dude doesn't receive our RESPONSE | ||
518 | * [which will contain the CHANGE] he will send another REQUEST which | ||
519 | * will "retrnasmit" the change. | ||
520 | */ | ||
521 | if (change && dp->dccps_role != DCCP_ROLE_LISTEN) { | ||
522 | dccp_pr_debug("reset feat negotiation timer %p\n", sk); | ||
523 | |||
524 | /* XXX don't reset the timer on re-transmissions. I.e. reset it | ||
525 | * only when sending new stuff i guess. Currently the timer | ||
526 | * never backs off because on re-transmission it just resets it! | ||
527 | */ | ||
528 | inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, | ||
529 | inet_csk(sk)->icsk_rto, DCCP_RTO_MAX); | ||
530 | } | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | int dccp_insert_options(struct sock *sk, struct sk_buff *skb) | ||
536 | { | ||
537 | struct dccp_sock *dp = dccp_sk(sk); | ||
538 | struct dccp_minisock *dmsk = dccp_msk(sk); | ||
427 | 539 | ||
428 | DCCP_SKB_CB(skb)->dccpd_opt_len = 0; | 540 | DCCP_SKB_CB(skb)->dccpd_opt_len = 0; |
429 | 541 | ||
430 | if (dp->dccps_options.dccpo_send_ndp_count) | 542 | if (dmsk->dccpms_send_ndp_count && |
431 | dccp_insert_option_ndp(sk, skb); | 543 | dccp_insert_option_ndp(sk, skb)) |
544 | return -1; | ||
432 | 545 | ||
433 | if (!dccp_packet_without_ack(skb)) { | 546 | if (!dccp_packet_without_ack(skb)) { |
434 | if (dp->dccps_options.dccpo_send_ack_vector && | 547 | if (dmsk->dccpms_send_ack_vector && |
435 | dccp_ackvec_pending(dp->dccps_hc_rx_ackvec)) | 548 | dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) && |
436 | dccp_insert_option_ackvec(sk, skb); | 549 | dccp_insert_option_ackvec(sk, skb)) |
437 | if (dp->dccps_timestamp_echo != 0) | 550 | return -1; |
438 | dccp_insert_option_timestamp_echo(sk, skb); | 551 | |
552 | if (dp->dccps_timestamp_echo != 0 && | ||
553 | dccp_insert_option_timestamp_echo(sk, skb)) | ||
554 | return -1; | ||
439 | } | 555 | } |
440 | 556 | ||
441 | if (dp->dccps_hc_rx_insert_options) { | 557 | if (dp->dccps_hc_rx_insert_options) { |
442 | ccid_hc_rx_insert_options(dp->dccps_hc_rx_ccid, sk, skb); | 558 | if (ccid_hc_rx_insert_options(dp->dccps_hc_rx_ccid, sk, skb)) |
559 | return -1; | ||
443 | dp->dccps_hc_rx_insert_options = 0; | 560 | dp->dccps_hc_rx_insert_options = 0; |
444 | } | 561 | } |
445 | if (dp->dccps_hc_tx_insert_options) { | 562 | if (dp->dccps_hc_tx_insert_options) { |
446 | ccid_hc_tx_insert_options(dp->dccps_hc_tx_ccid, sk, skb); | 563 | if (ccid_hc_tx_insert_options(dp->dccps_hc_tx_ccid, sk, skb)) |
564 | return -1; | ||
447 | dp->dccps_hc_tx_insert_options = 0; | 565 | dp->dccps_hc_tx_insert_options = 0; |
448 | } | 566 | } |
449 | 567 | ||
568 | /* Feature negotiation */ | ||
569 | /* Data packets can't do feat negotiation */ | ||
570 | if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA && | ||
571 | DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATAACK && | ||
572 | dccp_insert_options_feat(sk, skb)) | ||
573 | return -1; | ||
574 | |||
450 | /* XXX: insert other options when appropriate */ | 575 | /* XXX: insert other options when appropriate */ |
451 | 576 | ||
452 | if (DCCP_SKB_CB(skb)->dccpd_opt_len != 0) { | 577 | if (DCCP_SKB_CB(skb)->dccpd_opt_len != 0) { |
@@ -459,4 +584,6 @@ void dccp_insert_options(struct sock *sk, struct sk_buff *skb) | |||
459 | DCCP_SKB_CB(skb)->dccpd_opt_len += padding; | 584 | DCCP_SKB_CB(skb)->dccpd_opt_len += padding; |
460 | } | 585 | } |
461 | } | 586 | } |
587 | |||
588 | return 0; | ||
462 | } | 589 | } |