Blame view
net/dccp/options.c
16.5 KB
7c657876b [DCCP]: Initial i... |
1 2 3 4 |
/* * net/dccp/options.c * * An implementation of the DCCP protocol |
1bc098695 [DCCP]: Fix the t... |
5 6 |
* Copyright (c) 2005 Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> * Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@ghostprotocols.net> |
e6bccd357 [DCCP]: Update co... |
7 |
* Copyright (c) 2005 Ian McDonald <ian.mcdonald@jandi.co.nz> |
7c657876b [DCCP]: Initial i... |
8 9 10 11 12 13 |
* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ |
7c657876b [DCCP]: Initial i... |
14 15 16 |
#include <linux/dccp.h> #include <linux/module.h> #include <linux/types.h> |
76fd1e87d [DCCP]: Unaligned... |
17 |
#include <asm/unaligned.h> |
7c657876b [DCCP]: Initial i... |
18 19 |
#include <linux/kernel.h> #include <linux/skbuff.h> |
ae31c3399 [DCCP]: Move the ... |
20 |
#include "ackvec.h" |
7c657876b [DCCP]: Initial i... |
21 22 |
#include "ccid.h" #include "dccp.h" |
afe00251d [DCCP]: Initial f... |
23 |
#include "feat.h" |
7c657876b [DCCP]: Initial i... |
24 |
|
02fa460ef dccp: Increase th... |
25 |
u64 dccp_decode_value_var(const u8 *bf, const u8 len) |
7c657876b [DCCP]: Initial i... |
26 |
{ |
02fa460ef dccp: Increase th... |
27 |
u64 value = 0; |
7c657876b [DCCP]: Initial i... |
28 |
|
02fa460ef dccp: Increase th... |
29 30 31 32 |
if (len >= DCCP_OPTVAL_MAXLEN) value += ((u64)*bf++) << 40; if (len > 4) value += ((u64)*bf++) << 32; |
7c657876b [DCCP]: Initial i... |
33 |
if (len > 3) |
02fa460ef dccp: Increase th... |
34 |
value += ((u64)*bf++) << 24; |
7c657876b [DCCP]: Initial i... |
35 |
if (len > 2) |
02fa460ef dccp: Increase th... |
36 |
value += ((u64)*bf++) << 16; |
7c657876b [DCCP]: Initial i... |
37 |
if (len > 1) |
02fa460ef dccp: Increase th... |
38 |
value += ((u64)*bf++) << 8; |
7c657876b [DCCP]: Initial i... |
39 40 41 42 43 |
if (len > 0) value += *bf; return value; } |
8b8194124 [DCCP]: Allow to ... |
44 45 46 47 48 49 50 |
/** * dccp_parse_options - Parse DCCP options present in @skb * @sk: client|server|listening dccp socket (when @dreq != NULL) * @dreq: request socket to use during connection setup, or NULL */ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq, struct sk_buff *skb) |
7c657876b [DCCP]: Initial i... |
51 52 |
{ struct dccp_sock *dp = dccp_sk(sk); |
7c657876b [DCCP]: Initial i... |
53 54 55 56 |
const struct dccp_hdr *dh = dccp_hdr(skb); const u8 pkt_type = DCCP_SKB_CB(skb)->dccpd_type; unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb); unsigned char *opt_ptr = options; |
7690af3ff [DCCP]: Just refl... |
57 58 |
const unsigned char *opt_end = (unsigned char *)dh + (dh->dccph_doff * 4); |
7c657876b [DCCP]: Initial i... |
59 60 |
struct dccp_options_received *opt_recv = &dp->dccps_options_received; unsigned char opt, len; |
3ed7cc0f8 dccp: fix warning... |
61 |
unsigned char *uninitialized_var(value); |
1c14ac0ae [DCCP] Give prece... |
62 |
u32 elapsed_time; |
76fd1e87d [DCCP]: Unaligned... |
63 |
__be32 opt_val; |
afe00251d [DCCP]: Initial f... |
64 65 |
int rc; int mandatory = 0; |
7c657876b [DCCP]: Initial i... |
66 67 |
memset(opt_recv, 0, sizeof(*opt_recv)); |
fb9504964 [DCCP]: Fix unini... |
68 |
opt = len = 0; |
7c657876b [DCCP]: Initial i... |
69 70 71 72 73 74 75 76 |
while (opt_ptr != opt_end) { opt = *opt_ptr++; len = 0; value = NULL; /* Check if this isn't a single byte option */ if (opt > DCCPO_MAX_RESERVED) { if (opt_ptr == opt_end) |
faf61c331 dccp: Silently ig... |
77 |
goto out_nonsensical_length; |
7c657876b [DCCP]: Initial i... |
78 79 |
len = *opt_ptr++; |
faf61c331 dccp: Silently ig... |
80 81 |
if (len < 2) goto out_nonsensical_length; |
7c657876b [DCCP]: Initial i... |
82 83 84 85 86 87 88 89 90 |
/* * Remove the type and len fields, leaving * just the value size */ len -= 2; value = opt_ptr; opt_ptr += len; if (opt_ptr > opt_end) |
faf61c331 dccp: Silently ig... |
91 |
goto out_nonsensical_length; |
7c657876b [DCCP]: Initial i... |
92 |
} |
8b8194124 [DCCP]: Allow to ... |
93 |
/* |
8b8194124 [DCCP]: Allow to ... |
94 95 |
* CCID-specific options are ignored during connection setup, as * negotiation may still be in progress (see RFC 4340, 10.3). |
65907a433 dccp ccid-2: Bug-... |
96 |
* The same applies to Ack Vectors, as these depend on the CCID. |
8b8194124 [DCCP]: Allow to ... |
97 |
*/ |
a18213d1d dccp: Replace mag... |
98 |
if (dreq != NULL && (opt >= DCCPO_MIN_RX_CCID_SPECIFIC || |
65907a433 dccp ccid-2: Bug-... |
99 |
opt == DCCPO_ACK_VECTOR_0 || opt == DCCPO_ACK_VECTOR_1)) |
8b8194124 [DCCP]: Allow to ... |
100 |
goto ignore_option; |
7c657876b [DCCP]: Initial i... |
101 102 103 |
switch (opt) { case DCCPO_PADDING: break; |
afe00251d [DCCP]: Initial f... |
104 105 106 |
case DCCPO_MANDATORY: if (mandatory) goto out_invalid_option; |
6df9424a9 [DCCP] options: F... |
107 108 |
if (pkt_type != DCCP_PKT_DATA) mandatory = 1; |
afe00251d [DCCP]: Initial f... |
109 |
break; |
7c657876b [DCCP]: Initial i... |
110 |
case DCCPO_NDP_COUNT: |
5b5d0e704 dccp: Upgrade NDP... |
111 |
if (len > 6) |
7c657876b [DCCP]: Initial i... |
112 113 114 |
goto out_invalid_option; opt_recv->dccpor_ndp = dccp_decode_value_var(value, len); |
5b5d0e704 dccp: Upgrade NDP... |
115 116 117 |
dccp_pr_debug("%s opt: NDP count=%llu ", dccp_role(sk), (unsigned long long)opt_recv->dccpor_ndp); |
7c657876b [DCCP]: Initial i... |
118 |
break; |
b1ad00422 dccp: Processing ... |
119 120 |
case DCCPO_CHANGE_L ... DCCPO_CONFIRM_R: if (pkt_type == DCCP_PKT_DATA) /* RFC 4340, 6 */ |
cf86314cb [DCCP]: Ignore fe... |
121 |
break; |
a29486597 dccp: handle inva... |
122 123 |
if (len == 0) goto out_invalid_option; |
e77b8363b dccp: Process inc... |
124 125 126 127 |
rc = dccp_feat_parse_options(sk, dreq, mandatory, opt, *value, value + 1, len - 1); if (rc) goto out_featneg_failed; |
410e27a49 This reverts "Mer... |
128 |
break; |
7c657876b [DCCP]: Initial i... |
129 130 131 |
case DCCPO_TIMESTAMP: if (len != 4) goto out_invalid_option; |
b4d4f7c70 [DCCP]: Handle ti... |
132 133 134 135 136 |
/* * RFC 4340 13.1: "The precise time corresponding to * Timestamp Value zero is not specified". We use * zero to indicate absence of a meaningful timestamp. */ |
76fd1e87d [DCCP]: Unaligned... |
137 |
opt_val = get_unaligned((__be32 *)value); |
b4d4f7c70 [DCCP]: Handle ti... |
138 139 140 141 142 |
if (unlikely(opt_val == 0)) { DCCP_WARN("Timestamp with zero value "); break; } |
7c657876b [DCCP]: Initial i... |
143 |
|
b4d4f7c70 [DCCP]: Handle ti... |
144 145 146 147 148 149 150 151 |
if (dreq != NULL) { dreq->dreq_timestamp_echo = ntohl(opt_val); dreq->dreq_timestamp_time = dccp_timestamp(); } else { opt_recv->dccpor_timestamp = dp->dccps_timestamp_echo = ntohl(opt_val); dp->dccps_timestamp_time = dccp_timestamp(); } |
09dbc3895 [DCCP]: Miscellan... |
152 153 |
dccp_pr_debug("%s rx opt: TIMESTAMP=%u, ackno=%llu ", |
b4d4f7c70 [DCCP]: Handle ti... |
154 |
dccp_role(sk), ntohl(opt_val), |
f6ccf5541 [DCCP]: Fix u64 p... |
155 |
(unsigned long long) |
7c657876b [DCCP]: Initial i... |
156 |
DCCP_SKB_CB(skb)->dccpd_ack_seq); |
ecdfbdabb dccp: schedule an... |
157 158 |
/* schedule an Ack in case this sender is quiescent */ inet_csk_schedule_ack(sk); |
7c657876b [DCCP]: Initial i... |
159 160 |
break; case DCCPO_TIMESTAMP_ECHO: |
1bc098695 [DCCP]: Fix the t... |
161 |
if (len != 4 && len != 6 && len != 8) |
7c657876b [DCCP]: Initial i... |
162 |
goto out_invalid_option; |
76fd1e87d [DCCP]: Unaligned... |
163 164 |
opt_val = get_unaligned((__be32 *)value); opt_recv->dccpor_timestamp_echo = ntohl(opt_val); |
7c657876b [DCCP]: Initial i... |
165 |
|
09dbc3895 [DCCP]: Miscellan... |
166 |
dccp_pr_debug("%s rx opt: TIMESTAMP_ECHO=%u, len=%d, " |
f73f7097c [DCCP]: Debug sta... |
167 |
"ackno=%llu", dccp_role(sk), |
7690af3ff [DCCP]: Just refl... |
168 |
opt_recv->dccpor_timestamp_echo, |
f6ccf5541 [DCCP]: Fix u64 p... |
169 170 |
len + 2, (unsigned long long) |
1bc098695 [DCCP]: Fix the t... |
171 |
DCCP_SKB_CB(skb)->dccpd_ack_seq); |
76fd1e87d [DCCP]: Unaligned... |
172 |
value += 4; |
1bc098695 [DCCP]: Fix the t... |
173 |
|
76fd1e87d [DCCP]: Unaligned... |
174 |
if (len == 4) { /* no elapsed time included */ |
f73f7097c [DCCP]: Debug sta... |
175 176 |
dccp_pr_debug_cat(" "); |
1c14ac0ae [DCCP] Give prece... |
177 |
break; |
f73f7097c [DCCP]: Debug sta... |
178 |
} |
1c14ac0ae [DCCP] Give prece... |
179 |
|
76fd1e87d [DCCP]: Unaligned... |
180 181 182 183 184 185 186 |
if (len == 6) { /* 2-byte elapsed time */ __be16 opt_val2 = get_unaligned((__be16 *)value); elapsed_time = ntohs(opt_val2); } else { /* 4-byte elapsed time */ opt_val = get_unaligned((__be32 *)value); elapsed_time = ntohl(opt_val); } |
1c14ac0ae [DCCP] Give prece... |
187 |
|
dcad856fe [DCCP]: Wrong for... |
188 189 |
dccp_pr_debug_cat(", ELAPSED_TIME=%u ", elapsed_time); |
f73f7097c [DCCP]: Debug sta... |
190 |
|
1c14ac0ae [DCCP] Give prece... |
191 192 193 |
/* Give precedence to the biggest ELAPSED_TIME */ if (elapsed_time > opt_recv->dccpor_elapsed_time) opt_recv->dccpor_elapsed_time = elapsed_time; |
7c657876b [DCCP]: Initial i... |
194 195 |
break; case DCCPO_ELAPSED_TIME: |
c86ab2b6a [DCCP]: Ignore Ac... |
196 197 |
if (dccp_packet_without_ack(skb)) /* RFC 4340, 13.2 */ break; |
1bc098695 [DCCP]: Fix the t... |
198 |
|
76fd1e87d [DCCP]: Unaligned... |
199 200 201 |
if (len == 2) { __be16 opt_val2 = get_unaligned((__be16 *)value); elapsed_time = ntohs(opt_val2); |
c86ab2b6a [DCCP]: Ignore Ac... |
202 |
} else if (len == 4) { |
76fd1e87d [DCCP]: Unaligned... |
203 204 |
opt_val = get_unaligned((__be32 *)value); elapsed_time = ntohl(opt_val); |
c86ab2b6a [DCCP]: Ignore Ac... |
205 206 |
} else { goto out_invalid_option; |
76fd1e87d [DCCP]: Unaligned... |
207 |
} |
1c14ac0ae [DCCP] Give prece... |
208 209 210 |
if (elapsed_time > opt_recv->dccpor_elapsed_time) opt_recv->dccpor_elapsed_time = elapsed_time; |
1bc098695 [DCCP]: Fix the t... |
211 |
|
09dbc3895 [DCCP]: Miscellan... |
212 213 214 |
dccp_pr_debug("%s rx opt: ELAPSED_TIME=%d ", dccp_role(sk), elapsed_time); |
7c657876b [DCCP]: Initial i... |
215 |
break; |
a18213d1d dccp: Replace mag... |
216 |
case DCCPO_MIN_RX_CCID_SPECIFIC ... DCCPO_MAX_RX_CCID_SPECIFIC: |
7690af3ff [DCCP]: Just refl... |
217 |
if (ccid_hc_rx_parse_options(dp->dccps_hc_rx_ccid, sk, |
4874c131d dccp: Add packet ... |
218 |
pkt_type, opt, value, len)) |
7c657876b [DCCP]: Initial i... |
219 |
goto out_invalid_option; |
7c657876b [DCCP]: Initial i... |
220 |
break; |
7e87fe843 dccp ccid-2: Sepa... |
221 222 223 224 225 226 227 228 229 230 |
case DCCPO_ACK_VECTOR_0: case DCCPO_ACK_VECTOR_1: if (dccp_packet_without_ack(skb)) /* RFC 4340, 11.4 */ break; /* * Ack vectors are processed by the TX CCID if it is * interested. The RX CCID need not parse Ack Vectors, * since it is only interested in clearing old state. * Fall through. */ |
a18213d1d dccp: Replace mag... |
231 |
case DCCPO_MIN_TX_CCID_SPECIFIC ... DCCPO_MAX_TX_CCID_SPECIFIC: |
7690af3ff [DCCP]: Just refl... |
232 |
if (ccid_hc_tx_parse_options(dp->dccps_hc_tx_ccid, sk, |
4874c131d dccp: Add packet ... |
233 |
pkt_type, opt, value, len)) |
7c657876b [DCCP]: Initial i... |
234 |
goto out_invalid_option; |
7c657876b [DCCP]: Initial i... |
235 236 |
break; default: |
59348b19e [DCCP]: Simplifie... |
237 238 |
DCCP_CRIT("DCCP(%p): option %d(len=%d) not " "implemented, ignoring", sk, opt, len); |
7c657876b [DCCP]: Initial i... |
239 |
break; |
c9eaf1734 [NET] DCCP: Fix w... |
240 |
} |
8b8194124 [DCCP]: Allow to ... |
241 |
ignore_option: |
afe00251d [DCCP]: Initial f... |
242 243 |
if (opt != DCCPO_MANDATORY) mandatory = 0; |
7c657876b [DCCP]: Initial i... |
244 |
} |
6df9424a9 [DCCP] options: F... |
245 246 247 |
/* mandatory was the last byte in option list -> reset connection */ if (mandatory) goto out_invalid_option; |
faf61c331 dccp: Silently ig... |
248 249 |
out_nonsensical_length: /* RFC 4340, 5.8: ignore option and all remaining option space */ |
7c657876b [DCCP]: Initial i... |
250 251 252 |
return 0; out_invalid_option: |
7309f8821 dccp: do not assu... |
253 |
DCCP_INC_STATS(DCCP_MIB_INVALIDOPT); |
e77b8363b dccp: Process inc... |
254 255 256 257 258 |
rc = DCCP_RESET_CODE_OPTION_ERROR; out_featneg_failed: DCCP_WARN("DCCP(%p): Option %d (len=%d) error=%u ", sk, opt, len, rc); DCCP_SKB_CB(skb)->dccpd_reset_code = rc; |
eac7726bf dccp: Fill in the... |
259 260 261 |
DCCP_SKB_CB(skb)->dccpd_reset_data[0] = opt; DCCP_SKB_CB(skb)->dccpd_reset_data[1] = len > 0 ? value[0] : 0; DCCP_SKB_CB(skb)->dccpd_reset_data[2] = len > 1 ? value[1] : 0; |
7c657876b [DCCP]: Initial i... |
262 263 |
return -1; } |
b61fafc4e [DCCP]: Move the ... |
264 |
EXPORT_SYMBOL_GPL(dccp_parse_options); |
02fa460ef dccp: Increase th... |
265 |
void dccp_encode_value_var(const u64 value, u8 *to, const u8 len) |
7c657876b [DCCP]: Initial i... |
266 |
{ |
02fa460ef dccp: Increase th... |
267 268 269 270 |
if (len >= DCCP_OPTVAL_MAXLEN) *to++ = (value & 0xFF0000000000ull) >> 40; if (len > 4) *to++ = (value & 0xFF00000000ull) >> 32; |
7c657876b [DCCP]: Initial i... |
271 272 273 274 275 276 277 278 279 |
if (len > 3) *to++ = (value & 0xFF000000) >> 24; if (len > 2) *to++ = (value & 0xFF0000) >> 16; if (len > 1) *to++ = (value & 0xFF00) >> 8; if (len > 0) *to++ = (value & 0xFF); } |
5b5d0e704 dccp: Upgrade NDP... |
280 |
static inline u8 dccp_ndp_len(const u64 ndp) |
7c657876b [DCCP]: Initial i... |
281 |
{ |
5b5d0e704 dccp: Upgrade NDP... |
282 283 |
if (likely(ndp <= 0xFF)) return 1; |
4be929be3 kernel-wide: repl... |
284 |
return likely(ndp <= USHRT_MAX) ? 2 : (ndp <= UINT_MAX ? 4 : 6); |
7c657876b [DCCP]: Initial i... |
285 |
} |
a7d13fbf8 dccp: remove unus... |
286 287 |
int dccp_insert_option(struct sk_buff *skb, const unsigned char option, const void *value, const unsigned char len) |
7c657876b [DCCP]: Initial i... |
288 289 |
{ unsigned char *to; |
2d0817d11 [DCCP] options: M... |
290 291 |
if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 2 > DCCP_MAX_OPT_LEN) return -1; |
7c657876b [DCCP]: Initial i... |
292 293 294 295 296 297 298 299 |
DCCP_SKB_CB(skb)->dccpd_opt_len += len + 2; to = skb_push(skb, len + 2); *to++ = option; *to++ = len + 2; memcpy(to, value, len); |
2d0817d11 [DCCP] options: M... |
300 |
return 0; |
7c657876b [DCCP]: Initial i... |
301 302 303 |
} EXPORT_SYMBOL_GPL(dccp_insert_option); |
2d0817d11 [DCCP] options: M... |
304 |
static int dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb) |
7c657876b [DCCP]: Initial i... |
305 306 |
{ struct dccp_sock *dp = dccp_sk(sk); |
5b5d0e704 dccp: Upgrade NDP... |
307 |
u64 ndp = dp->dccps_ndp_count; |
7c657876b [DCCP]: Initial i... |
308 309 310 311 312 313 314 315 316 317 318 319 |
if (dccp_non_data_packet(skb)) ++dp->dccps_ndp_count; else dp->dccps_ndp_count = 0; if (ndp > 0) { unsigned char *ptr; const int ndp_len = dccp_ndp_len(ndp); const int len = ndp_len + 2; if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) |
2d0817d11 [DCCP] options: M... |
320 |
return -1; |
7c657876b [DCCP]: Initial i... |
321 322 323 324 325 326 327 328 |
DCCP_SKB_CB(skb)->dccpd_opt_len += len; ptr = skb_push(skb, len); *ptr++ = DCCPO_NDP_COUNT; *ptr++ = len; dccp_encode_value_var(ndp, ptr, ndp_len); } |
2d0817d11 [DCCP] options: M... |
329 330 |
return 0; |
7c657876b [DCCP]: Initial i... |
331 332 333 334 |
} static inline int dccp_elapsed_time_len(const u32 elapsed_time) { |
b1c9fe7b8 [DCCP]: Fix elaps... |
335 |
return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4; |
7c657876b [DCCP]: Initial i... |
336 |
} |
1f4f0f645 dccp: Kill dead c... |
337 |
static int dccp_insert_option_timestamp(struct sk_buff *skb) |
7c657876b [DCCP]: Initial i... |
338 |
{ |
4c70f383e [DCCP]: Provide 1... |
339 |
__be32 now = htonl(dccp_timestamp()); |
1bc098695 [DCCP]: Fix the t... |
340 341 |
/* yes this will overflow but that is the point as we want a * 10 usec 32 bit timer which mean it wraps every 11.9 hours */ |
a7d13fbf8 dccp: remove unus... |
342 |
return dccp_insert_option(skb, DCCPO_TIMESTAMP, &now, sizeof(now)); |
7c657876b [DCCP]: Initial i... |
343 |
} |
b4d4f7c70 [DCCP]: Handle ti... |
344 345 |
static int dccp_insert_option_timestamp_echo(struct dccp_sock *dp, struct dccp_request_sock *dreq, |
2d0817d11 [DCCP] options: M... |
346 |
struct sk_buff *skb) |
7c657876b [DCCP]: Initial i... |
347 |
{ |
60fe62e78 [DCCP]: sparse en... |
348 |
__be32 tstamp_echo; |
7c657876b [DCCP]: Initial i... |
349 |
unsigned char *to; |
b4d4f7c70 [DCCP]: Handle ti... |
350 351 352 353 354 355 356 357 358 359 360 |
u32 elapsed_time, elapsed_time_len, len; if (dreq != NULL) { elapsed_time = dccp_timestamp() - dreq->dreq_timestamp_time; tstamp_echo = htonl(dreq->dreq_timestamp_echo); dreq->dreq_timestamp_echo = 0; } else { elapsed_time = dccp_timestamp() - dp->dccps_timestamp_time; tstamp_echo = htonl(dp->dccps_timestamp_echo); dp->dccps_timestamp_echo = 0; } |
b0e567806 [DCCP] Introduce ... |
361 362 |
elapsed_time_len = dccp_elapsed_time_len(elapsed_time); len = 6 + elapsed_time_len; |
2d0817d11 [DCCP] options: M... |
363 364 |
if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) return -1; |
7c657876b [DCCP]: Initial i... |
365 366 367 368 369 370 |
DCCP_SKB_CB(skb)->dccpd_opt_len += len; to = skb_push(skb, len); *to++ = DCCPO_TIMESTAMP_ECHO; *to++ = len; |
7c657876b [DCCP]: Initial i... |
371 372 |
memcpy(to, &tstamp_echo, 4); to += 4; |
afe00251d [DCCP]: Initial f... |
373 |
|
1bc098695 [DCCP]: Fix the t... |
374 |
if (elapsed_time_len == 2) { |
60fe62e78 [DCCP]: sparse en... |
375 |
const __be16 var16 = htons((u16)elapsed_time); |
1bc098695 [DCCP]: Fix the t... |
376 377 |
memcpy(to, &var16, 2); } else if (elapsed_time_len == 4) { |
60fe62e78 [DCCP]: sparse en... |
378 |
const __be32 var32 = htonl(elapsed_time); |
1bc098695 [DCCP]: Fix the t... |
379 380 |
memcpy(to, &var32, 4); } |
7c657876b [DCCP]: Initial i... |
381 |
|
2d0817d11 [DCCP] options: M... |
382 |
return 0; |
7c657876b [DCCP]: Initial i... |
383 |
} |
7d8709366 dccp ccid-2: Sepa... |
384 385 386 387 |
static int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) { struct dccp_sock *dp = dccp_sk(sk); struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; |
d83447f09 dccp ccid-2: Sche... |
388 |
struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); |
b3d14bff1 dccp ccid-2: Impl... |
389 |
const u16 buflen = dccp_ackvec_buflen(av); |
7d8709366 dccp ccid-2: Sepa... |
390 |
/* Figure out how many options do we need to represent the ackvec */ |
b3d14bff1 dccp ccid-2: Impl... |
391 392 |
const u8 nr_opts = DIV_ROUND_UP(buflen, DCCP_SINGLE_OPT_MAXLEN); u16 len = buflen + 2 * nr_opts; |
7d8709366 dccp ccid-2: Sepa... |
393 394 395 |
u8 i, nonce = 0; const unsigned char *tail, *from; unsigned char *to; |
d83447f09 dccp ccid-2: Sche... |
396 397 398 399 |
if (dcb->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) { DCCP_WARN("Lacking space for %u bytes on %s packet ", len, dccp_packet_name(dcb->dccpd_type)); |
7d8709366 dccp ccid-2: Sepa... |
400 |
return -1; |
d83447f09 dccp ccid-2: Sche... |
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 |
} /* * Since Ack Vectors are variable-length, we can not always predict * their size. To catch exception cases where the space is running out * on the skb, a separate Sync is scheduled to carry the Ack Vector. */ if (len > DCCPAV_MIN_OPTLEN && len + dcb->dccpd_opt_len + skb->len > dp->dccps_mss_cache) { DCCP_WARN("No space left for Ack Vector (%u) on skb (%u+%u), " "MPS=%u ==> reduce payload size? ", len, skb->len, dcb->dccpd_opt_len, dp->dccps_mss_cache); dp->dccps_sync_scheduled = 1; return 0; } dcb->dccpd_opt_len += len; |
7d8709366 dccp ccid-2: Sepa... |
417 418 |
to = skb_push(skb, len); |
b3d14bff1 dccp ccid-2: Impl... |
419 |
len = buflen; |
7d8709366 dccp ccid-2: Sepa... |
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 |
from = av->av_buf + av->av_buf_head; tail = av->av_buf + DCCPAV_MAX_ACKVEC_LEN; for (i = 0; i < nr_opts; ++i) { int copylen = len; if (len > DCCP_SINGLE_OPT_MAXLEN) copylen = DCCP_SINGLE_OPT_MAXLEN; /* * RFC 4340, 12.2: Encode the Nonce Echo for this Ack Vector via * its type; ack_nonce is the sum of all individual buf_nonce's. */ nonce ^= av->av_buf_nonce[i]; *to++ = DCCPO_ACK_VECTOR_0 + av->av_buf_nonce[i]; *to++ = copylen + 2; /* Check if buf_head wraps */ if (from + copylen > tail) { const u16 tailsize = tail - from; memcpy(to, from, tailsize); to += tailsize; len -= tailsize; copylen -= tailsize; from = av->av_buf; } memcpy(to, from, copylen); from += copylen; to += copylen; len -= copylen; } /* * Each sent Ack Vector is recorded in the list, as per A.2 of RFC 4340. */ |
d83447f09 dccp ccid-2: Sche... |
457 |
if (dccp_ackvec_update_records(av, dcb->dccpd_seq, nonce)) |
7d8709366 dccp ccid-2: Sepa... |
458 459 460 |
return -ENOBUFS; return 0; } |
d37105669 dccp: Support for... |
461 462 463 464 465 466 467 468 469 470 471 472 473 474 |
/** * dccp_insert_option_mandatory - Mandatory option (5.8.2) * Note that since we are using skb_push, this function needs to be called * _after_ inserting the option it is supposed to influence (stack order). */ int dccp_insert_option_mandatory(struct sk_buff *skb) { if (DCCP_SKB_CB(skb)->dccpd_opt_len >= DCCP_MAX_OPT_LEN) return -1; DCCP_SKB_CB(skb)->dccpd_opt_len++; *skb_push(skb, 1) = DCCPO_MANDATORY; return 0; } |
8c862c23e dccp: Header opti... |
475 476 477 478 479 480 481 |
/** * dccp_insert_fn_opt - Insert single Feature-Negotiation option into @skb * @type: %DCCPO_CHANGE_L, %DCCPO_CHANGE_R, %DCCPO_CONFIRM_L, %DCCPO_CONFIRM_R * @feat: one out of %dccp_feature_numbers * @val: NN value or SP array (preferred element first) to copy * @len: true length of @val in bytes (excluding first element repetition) * @repeat_first: whether to copy the first element of @val twice |
2c53040f0 net: Fix (nearly-... |
482 |
* |
8c862c23e dccp: Header opti... |
483 484 485 486 487 488 489 |
* The last argument is used to construct Confirm options, where the preferred * value and the preference list appear separately (RFC 4340, 6.3.1). Preference * lists are kept such that the preferred entry is always first, so we only need * to copy twice, and avoid the overhead of cloning into a bigger array. */ int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat, u8 *val, u8 len, bool repeat_first) |
4829007c7 dccp ccid-2: Sepa... |
490 |
{ |
8c862c23e dccp: Header opti... |
491 |
u8 tot_len, *to; |
4829007c7 dccp ccid-2: Sepa... |
492 |
|
8c862c23e dccp: Header opti... |
493 494 495 496 |
/* take the `Feature' field and possible repetition into account */ if (len > (DCCP_SINGLE_OPT_MAXLEN - 2)) { DCCP_WARN("length %u for feature %u too large ", len, feat); |
4829007c7 dccp ccid-2: Sepa... |
497 |
return -1; |
c2f42077b dccp ccid-2: Sche... |
498 |
} |
4829007c7 dccp ccid-2: Sepa... |
499 |
|
8c862c23e dccp: Header opti... |
500 |
if (unlikely(val == NULL || len == 0)) |
3db1cd5c0 net: fix assignme... |
501 |
len = repeat_first = false; |
8c862c23e dccp: Header opti... |
502 503 504 505 506 507 508 509 |
tot_len = 3 + repeat_first + len; if (DCCP_SKB_CB(skb)->dccpd_opt_len + tot_len > DCCP_MAX_OPT_LEN) { DCCP_WARN("packet too small for feature %d option! ", feat); return -1; } DCCP_SKB_CB(skb)->dccpd_opt_len += tot_len; |
4829007c7 dccp ccid-2: Sepa... |
510 |
|
8c862c23e dccp: Header opti... |
511 |
to = skb_push(skb, tot_len); |
410e27a49 This reverts "Mer... |
512 |
*to++ = type; |
8c862c23e dccp: Header opti... |
513 |
*to++ = tot_len; |
410e27a49 This reverts "Mer... |
514 |
*to++ = feat; |
4829007c7 dccp ccid-2: Sepa... |
515 |
|
8c862c23e dccp: Header opti... |
516 517 |
if (repeat_first) *to++ = *val; |
410e27a49 This reverts "Mer... |
518 519 |
if (len) memcpy(to, val, len); |
d0440ee6f dccp: Support for... |
520 521 |
return 0; } |
af3b867e2 [DCCP]: Support i... |
522 523 524 525 526 527 528 529 530 531 532 |
/* The length of all options needs to be a multiple of 4 (5.8) */ static void dccp_insert_option_padding(struct sk_buff *skb) { int padding = DCCP_SKB_CB(skb)->dccpd_opt_len % 4; if (padding != 0) { padding = 4 - padding; memset(skb_push(skb, padding), 0, padding); DCCP_SKB_CB(skb)->dccpd_opt_len += padding; } } |
2d0817d11 [DCCP] options: M... |
533 |
int dccp_insert_options(struct sock *sk, struct sk_buff *skb) |
7c657876b [DCCP]: Initial i... |
534 535 536 537 |
{ struct dccp_sock *dp = dccp_sk(sk); DCCP_SKB_CB(skb)->dccpd_opt_len = 0; |
4098dce5b dccp: Remove manu... |
538 |
if (dp->dccps_send_ndp_count && dccp_insert_option_ndp(sk, skb)) |
2d0817d11 [DCCP] options: M... |
539 |
return -1; |
7c657876b [DCCP]: Initial i... |
540 |
|
8b7b6c75c dccp: Integrate f... |
541 542 543 544 |
if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA) { /* Feature Negotiation */ if (dccp_feat_insert_opts(dp, NULL, skb)) |
2d0817d11 [DCCP] options: M... |
545 |
return -1; |
8b7b6c75c dccp: Integrate f... |
546 547 548 549 |
if (DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_REQUEST) { /* * Obtain RTT sample from Request/Response exchange. |
59b80802a dccp: make implem... |
550 |
* This is currently used for TFRC initialisation. |
8b7b6c75c dccp: Integrate f... |
551 |
*/ |
a7d13fbf8 dccp: remove unus... |
552 |
if (dccp_insert_option_timestamp(skb)) |
8b7b6c75c dccp: Integrate f... |
553 |
return -1; |
b3d14bff1 dccp ccid-2: Impl... |
554 |
} else if (dccp_ackvec_pending(sk) && |
8b7b6c75c dccp: Integrate f... |
555 556 557 |
dccp_insert_option_ackvec(sk, skb)) { return -1; } |
7c657876b [DCCP]: Initial i... |
558 |
} |
507d37cf2 [CCID] Only call ... |
559 |
if (dp->dccps_hc_rx_insert_options) { |
2d0817d11 [DCCP] options: M... |
560 561 |
if (ccid_hc_rx_insert_options(dp->dccps_hc_rx_ccid, sk, skb)) return -1; |
507d37cf2 [CCID] Only call ... |
562 563 |
dp->dccps_hc_rx_insert_options = 0; } |
7c657876b [DCCP]: Initial i... |
564 |
|
b4d4f7c70 [DCCP]: Handle ti... |
565 566 567 |
if (dp->dccps_timestamp_echo != 0 && dccp_insert_option_timestamp_echo(dp, NULL, skb)) return -1; |
af3b867e2 [DCCP]: Support i... |
568 569 570 |
dccp_insert_option_padding(skb); return 0; } |
7c657876b [DCCP]: Initial i... |
571 |
|
af3b867e2 [DCCP]: Support i... |
572 573 574 |
int dccp_insert_options_rsk(struct dccp_request_sock *dreq, struct sk_buff *skb) { DCCP_SKB_CB(skb)->dccpd_opt_len = 0; |
7c657876b [DCCP]: Initial i... |
575 |
|
8b7b6c75c dccp: Integrate f... |
576 577 |
if (dccp_feat_insert_opts(NULL, dreq, skb)) return -1; |
59b80802a dccp: make implem... |
578 579 580 |
/* Obtain RTT sample from Response/Ack exchange (used by TFRC). */ if (dccp_insert_option_timestamp(skb)) return -1; |
af3b867e2 [DCCP]: Support i... |
581 582 583 |
if (dreq->dreq_timestamp_echo != 0 && dccp_insert_option_timestamp_echo(NULL, dreq, skb)) return -1; |
2d0817d11 [DCCP] options: M... |
584 |
|
af3b867e2 [DCCP]: Support i... |
585 |
dccp_insert_option_padding(skb); |
2d0817d11 [DCCP] options: M... |
586 |
return 0; |
7c657876b [DCCP]: Initial i... |
587 |
} |