Blame view

net/dccp/options.c 16.5 KB
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
1
2
3
4
  /*
   *  net/dccp/options.c
   *
   *  An implementation of the DCCP protocol
1bc098695   Ian McDonald   [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   Ian McDonald   [DCCP]: Update co...
7
   *  Copyright (c) 2005 Ian McDonald <ian.mcdonald@jandi.co.nz>
7c657876b   Arnaldo Carvalho de Melo   [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   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
14
15
16
  #include <linux/dccp.h>
  #include <linux/module.h>
  #include <linux/types.h>
76fd1e87d   Gerrit Renker   [DCCP]: Unaligned...
17
  #include <asm/unaligned.h>
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
18
19
  #include <linux/kernel.h>
  #include <linux/skbuff.h>
ae31c3399   Arnaldo Carvalho de Melo   [DCCP]: Move the ...
20
  #include "ackvec.h"
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
21
22
  #include "ccid.h"
  #include "dccp.h"
afe00251d   Andrea Bittau   [DCCP]: Initial f...
23
  #include "feat.h"
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
24

02fa460ef   Gerrit Renker   dccp: Increase th...
25
  u64 dccp_decode_value_var(const u8 *bf, const u8 len)
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
26
  {
02fa460ef   Gerrit Renker   dccp: Increase th...
27
  	u64 value = 0;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
28

02fa460ef   Gerrit Renker   dccp: Increase th...
29
30
31
32
  	if (len >= DCCP_OPTVAL_MAXLEN)
  		value += ((u64)*bf++) << 40;
  	if (len > 4)
  		value += ((u64)*bf++) << 32;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
33
  	if (len > 3)
02fa460ef   Gerrit Renker   dccp: Increase th...
34
  		value += ((u64)*bf++) << 24;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
35
  	if (len > 2)
02fa460ef   Gerrit Renker   dccp: Increase th...
36
  		value += ((u64)*bf++) << 16;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
37
  	if (len > 1)
02fa460ef   Gerrit Renker   dccp: Increase th...
38
  		value += ((u64)*bf++) << 8;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
39
40
41
42
43
  	if (len > 0)
  		value += *bf;
  
  	return value;
  }
8b8194124   Gerrit Renker   [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   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
51
52
  {
  	struct dccp_sock *dp = dccp_sk(sk);
7c657876b   Arnaldo Carvalho de Melo   [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   Arnaldo Carvalho de Melo   [DCCP]: Just refl...
57
58
  	const unsigned char *opt_end = (unsigned char *)dh +
  					(dh->dccph_doff * 4);
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
59
60
  	struct dccp_options_received *opt_recv = &dp->dccps_options_received;
  	unsigned char opt, len;
3ed7cc0f8   Ingo Molnar   dccp: fix warning...
61
  	unsigned char *uninitialized_var(value);
1c14ac0ae   Arnaldo Carvalho de Melo   [DCCP] Give prece...
62
  	u32 elapsed_time;
76fd1e87d   Gerrit Renker   [DCCP]: Unaligned...
63
  	__be32 opt_val;
afe00251d   Andrea Bittau   [DCCP]: Initial f...
64
65
  	int rc;
  	int mandatory = 0;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
66
67
  
  	memset(opt_recv, 0, sizeof(*opt_recv));
fb9504964   David S. Miller   [DCCP]: Fix unini...
68
  	opt = len = 0;
7c657876b   Arnaldo Carvalho de Melo   [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   Gerrit Renker   dccp: Silently ig...
77
  				goto out_nonsensical_length;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
78
79
  
  			len = *opt_ptr++;
faf61c331   Gerrit Renker   dccp: Silently ig...
80
81
  			if (len < 2)
  				goto out_nonsensical_length;
7c657876b   Arnaldo Carvalho de Melo   [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   Gerrit Renker   dccp: Silently ig...
91
  				goto out_nonsensical_length;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
92
  		}
8b8194124   Gerrit Renker   [DCCP]: Allow to ...
93
  		/*
8b8194124   Gerrit Renker   [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   Gerrit Renker   dccp ccid-2: Bug-...
96
  		 * The same applies to Ack Vectors, as these depend on the CCID.
8b8194124   Gerrit Renker   [DCCP]: Allow to ...
97
  		 */
a18213d1d   Gerrit Renker   dccp: Replace mag...
98
  		if (dreq != NULL && (opt >= DCCPO_MIN_RX_CCID_SPECIFIC ||
65907a433   Gerrit Renker   dccp ccid-2: Bug-...
99
  		    opt == DCCPO_ACK_VECTOR_0 || opt == DCCPO_ACK_VECTOR_1))
8b8194124   Gerrit Renker   [DCCP]: Allow to ...
100
  			goto ignore_option;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
101
102
103
  		switch (opt) {
  		case DCCPO_PADDING:
  			break;
afe00251d   Andrea Bittau   [DCCP]: Initial f...
104
105
106
  		case DCCPO_MANDATORY:
  			if (mandatory)
  				goto out_invalid_option;
6df9424a9   Arnaldo Carvalho de Melo   [DCCP] options: F...
107
108
  			if (pkt_type != DCCP_PKT_DATA)
  				mandatory = 1;
afe00251d   Andrea Bittau   [DCCP]: Initial f...
109
  			break;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
110
  		case DCCPO_NDP_COUNT:
5b5d0e704   Gerrit Renker   dccp: Upgrade NDP...
111
  			if (len > 6)
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
112
113
114
  				goto out_invalid_option;
  
  			opt_recv->dccpor_ndp = dccp_decode_value_var(value, len);
5b5d0e704   Gerrit Renker   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   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
118
  			break;
b1ad00422   Gerrit Renker   dccp: Processing ...
119
120
  		case DCCPO_CHANGE_L ... DCCPO_CONFIRM_R:
  			if (pkt_type == DCCP_PKT_DATA)      /* RFC 4340, 6 */
cf86314cb   Gerrit Renker   [DCCP]: Ignore fe...
121
  				break;
a29486597   Dan Rosenberg   dccp: handle inva...
122
123
  			if (len == 0)
  				goto out_invalid_option;
e77b8363b   Gerrit Renker   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   Gerrit Renker   This reverts "Mer...
128
  			break;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
129
130
131
  		case DCCPO_TIMESTAMP:
  			if (len != 4)
  				goto out_invalid_option;
b4d4f7c70   Gerrit Renker   [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   Gerrit Renker   [DCCP]: Unaligned...
137
  			opt_val = get_unaligned((__be32 *)value);
b4d4f7c70   Gerrit Renker   [DCCP]: Handle ti...
138
139
140
141
142
  			if (unlikely(opt_val == 0)) {
  				DCCP_WARN("Timestamp with zero value
  ");
  				break;
  			}
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
143

b4d4f7c70   Gerrit Renker   [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   Gerrit Renker   [DCCP]: Miscellan...
152
153
  			dccp_pr_debug("%s rx opt: TIMESTAMP=%u, ackno=%llu
  ",
b4d4f7c70   Gerrit Renker   [DCCP]: Handle ti...
154
  				      dccp_role(sk), ntohl(opt_val),
f6ccf5541   David S. Miller   [DCCP]: Fix u64 p...
155
  				      (unsigned long long)
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
156
  				      DCCP_SKB_CB(skb)->dccpd_ack_seq);
ecdfbdabb   Gerrit Renker   dccp: schedule an...
157
158
  			/* schedule an Ack in case this sender is quiescent */
  			inet_csk_schedule_ack(sk);
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
159
160
  			break;
  		case DCCPO_TIMESTAMP_ECHO:
1bc098695   Ian McDonald   [DCCP]: Fix the t...
161
  			if (len != 4 && len != 6 && len != 8)
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
162
  				goto out_invalid_option;
76fd1e87d   Gerrit Renker   [DCCP]: Unaligned...
163
164
  			opt_val = get_unaligned((__be32 *)value);
  			opt_recv->dccpor_timestamp_echo = ntohl(opt_val);
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
165

09dbc3895   Gerrit Renker   [DCCP]: Miscellan...
166
  			dccp_pr_debug("%s rx opt: TIMESTAMP_ECHO=%u, len=%d, "
f73f7097c   Gerrit Renker   [DCCP]: Debug sta...
167
  				      "ackno=%llu", dccp_role(sk),
7690af3ff   Arnaldo Carvalho de Melo   [DCCP]: Just refl...
168
  				      opt_recv->dccpor_timestamp_echo,
f6ccf5541   David S. Miller   [DCCP]: Fix u64 p...
169
170
  				      len + 2,
  				      (unsigned long long)
1bc098695   Ian McDonald   [DCCP]: Fix the t...
171
  				      DCCP_SKB_CB(skb)->dccpd_ack_seq);
76fd1e87d   Gerrit Renker   [DCCP]: Unaligned...
172
  			value += 4;
1bc098695   Ian McDonald   [DCCP]: Fix the t...
173

76fd1e87d   Gerrit Renker   [DCCP]: Unaligned...
174
  			if (len == 4) {		/* no elapsed time included */
f73f7097c   Gerrit Renker   [DCCP]: Debug sta...
175
176
  				dccp_pr_debug_cat("
  ");
1c14ac0ae   Arnaldo Carvalho de Melo   [DCCP] Give prece...
177
  				break;
f73f7097c   Gerrit Renker   [DCCP]: Debug sta...
178
  			}
1c14ac0ae   Arnaldo Carvalho de Melo   [DCCP] Give prece...
179

76fd1e87d   Gerrit Renker   [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   Arnaldo Carvalho de Melo   [DCCP] Give prece...
187

dcad856fe   Gerrit Renker   [DCCP]: Wrong for...
188
189
  			dccp_pr_debug_cat(", ELAPSED_TIME=%u
  ", elapsed_time);
f73f7097c   Gerrit Renker   [DCCP]: Debug sta...
190

1c14ac0ae   Arnaldo Carvalho de Melo   [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   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
194
195
  			break;
  		case DCCPO_ELAPSED_TIME:
c86ab2b6a   Gerrit Renker   [DCCP]: Ignore Ac...
196
197
  			if (dccp_packet_without_ack(skb))   /* RFC 4340, 13.2 */
  				break;
1bc098695   Ian McDonald   [DCCP]: Fix the t...
198

76fd1e87d   Gerrit Renker   [DCCP]: Unaligned...
199
200
201
  			if (len == 2) {
  				__be16 opt_val2 = get_unaligned((__be16 *)value);
  				elapsed_time = ntohs(opt_val2);
c86ab2b6a   Gerrit Renker   [DCCP]: Ignore Ac...
202
  			} else if (len == 4) {
76fd1e87d   Gerrit Renker   [DCCP]: Unaligned...
203
204
  				opt_val = get_unaligned((__be32 *)value);
  				elapsed_time = ntohl(opt_val);
c86ab2b6a   Gerrit Renker   [DCCP]: Ignore Ac...
205
206
  			} else {
  				goto out_invalid_option;
76fd1e87d   Gerrit Renker   [DCCP]: Unaligned...
207
  			}
1c14ac0ae   Arnaldo Carvalho de Melo   [DCCP] Give prece...
208
209
210
  
  			if (elapsed_time > opt_recv->dccpor_elapsed_time)
  				opt_recv->dccpor_elapsed_time = elapsed_time;
1bc098695   Ian McDonald   [DCCP]: Fix the t...
211

09dbc3895   Gerrit Renker   [DCCP]: Miscellan...
212
213
214
  			dccp_pr_debug("%s rx opt: ELAPSED_TIME=%d
  ",
  				      dccp_role(sk), elapsed_time);
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
215
  			break;
a18213d1d   Gerrit Renker   dccp: Replace mag...
216
  		case DCCPO_MIN_RX_CCID_SPECIFIC ... DCCPO_MAX_RX_CCID_SPECIFIC:
7690af3ff   Arnaldo Carvalho de Melo   [DCCP]: Just refl...
217
  			if (ccid_hc_rx_parse_options(dp->dccps_hc_rx_ccid, sk,
4874c131d   Gerrit Renker   dccp: Add packet ...
218
  						     pkt_type, opt, value, len))
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
219
  				goto out_invalid_option;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
220
  			break;
7e87fe843   Gerrit Renker   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   Gerrit Renker   dccp: Replace mag...
231
  		case DCCPO_MIN_TX_CCID_SPECIFIC ... DCCPO_MAX_TX_CCID_SPECIFIC:
7690af3ff   Arnaldo Carvalho de Melo   [DCCP]: Just refl...
232
  			if (ccid_hc_tx_parse_options(dp->dccps_hc_tx_ccid, sk,
4874c131d   Gerrit Renker   dccp: Add packet ...
233
  						     pkt_type, opt, value, len))
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
234
  				goto out_invalid_option;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
235
236
  			break;
  		default:
59348b19e   Gerrit Renker   [DCCP]: Simplifie...
237
238
  			DCCP_CRIT("DCCP(%p): option %d(len=%d) not "
  				  "implemented, ignoring", sk, opt, len);
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
239
  			break;
c9eaf1734   YOSHIFUJI Hideaki   [NET] DCCP: Fix w...
240
  		}
8b8194124   Gerrit Renker   [DCCP]: Allow to ...
241
  ignore_option:
afe00251d   Andrea Bittau   [DCCP]: Initial f...
242
243
  		if (opt != DCCPO_MANDATORY)
  			mandatory = 0;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
244
  	}
6df9424a9   Arnaldo Carvalho de Melo   [DCCP] options: F...
245
246
247
  	/* mandatory was the last byte in option list -> reset connection */
  	if (mandatory)
  		goto out_invalid_option;
faf61c331   Gerrit Renker   dccp: Silently ig...
248
249
  out_nonsensical_length:
  	/* RFC 4340, 5.8: ignore option and all remaining option space */
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
250
251
252
  	return 0;
  
  out_invalid_option:
7309f8821   Eric Dumazet   dccp: do not assu...
253
  	DCCP_INC_STATS(DCCP_MIB_INVALIDOPT);
e77b8363b   Gerrit Renker   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   Gerrit Renker   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   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
262
263
  	return -1;
  }
b61fafc4e   Arnaldo Carvalho de Melo   [DCCP]: Move the ...
264
  EXPORT_SYMBOL_GPL(dccp_parse_options);
02fa460ef   Gerrit Renker   dccp: Increase th...
265
  void dccp_encode_value_var(const u64 value, u8 *to, const u8 len)
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
266
  {
02fa460ef   Gerrit Renker   dccp: Increase th...
267
268
269
270
  	if (len >= DCCP_OPTVAL_MAXLEN)
  		*to++ = (value & 0xFF0000000000ull) >> 40;
  	if (len > 4)
  		*to++ = (value & 0xFF00000000ull) >> 32;
7c657876b   Arnaldo Carvalho de Melo   [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   Gerrit Renker   dccp: Upgrade NDP...
280
  static inline u8 dccp_ndp_len(const u64 ndp)
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
281
  {
5b5d0e704   Gerrit Renker   dccp: Upgrade NDP...
282
283
  	if (likely(ndp <= 0xFF))
  		return 1;
4be929be3   Alexey Dobriyan   kernel-wide: repl...
284
  	return likely(ndp <= USHRT_MAX) ? 2 : (ndp <= UINT_MAX ? 4 : 6);
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
285
  }
a7d13fbf8   Gerrit Renker   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   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
288
289
  {
  	unsigned char *to;
2d0817d11   Arnaldo Carvalho de Melo   [DCCP] options: M...
290
291
  	if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 2 > DCCP_MAX_OPT_LEN)
  		return -1;
7c657876b   Arnaldo Carvalho de Melo   [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   Arnaldo Carvalho de Melo   [DCCP] options: M...
300
  	return 0;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
301
302
303
  }
  
  EXPORT_SYMBOL_GPL(dccp_insert_option);
2d0817d11   Arnaldo Carvalho de Melo   [DCCP] options: M...
304
  static int dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb)
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
305
306
  {
  	struct dccp_sock *dp = dccp_sk(sk);
5b5d0e704   Gerrit Renker   dccp: Upgrade NDP...
307
  	u64 ndp = dp->dccps_ndp_count;
7c657876b   Arnaldo Carvalho de Melo   [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   Arnaldo Carvalho de Melo   [DCCP] options: M...
320
  			return -1;
7c657876b   Arnaldo Carvalho de Melo   [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   Arnaldo Carvalho de Melo   [DCCP] options: M...
329
330
  
  	return 0;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
331
332
333
334
  }
  
  static inline int dccp_elapsed_time_len(const u32 elapsed_time)
  {
b1c9fe7b8   Ian McDonald   [DCCP]: Fix elaps...
335
  	return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
336
  }
1f4f0f645   stephen hemminger   dccp: Kill dead c...
337
  static int dccp_insert_option_timestamp(struct sk_buff *skb)
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
338
  {
4c70f383e   Gerrit Renker   [DCCP]: Provide 1...
339
  	__be32 now = htonl(dccp_timestamp());
1bc098695   Ian McDonald   [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   Gerrit Renker   dccp: remove unus...
342
  	return dccp_insert_option(skb, DCCPO_TIMESTAMP, &now, sizeof(now));
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
343
  }
b4d4f7c70   Gerrit Renker   [DCCP]: Handle ti...
344
345
  static int dccp_insert_option_timestamp_echo(struct dccp_sock *dp,
  					     struct dccp_request_sock *dreq,
2d0817d11   Arnaldo Carvalho de Melo   [DCCP] options: M...
346
  					     struct sk_buff *skb)
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
347
  {
60fe62e78   Andrea Bittau   [DCCP]: sparse en...
348
  	__be32 tstamp_echo;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
349
  	unsigned char *to;
b4d4f7c70   Gerrit Renker   [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   Arnaldo Carvalho de Melo   [DCCP] Introduce ...
361
362
  	elapsed_time_len = dccp_elapsed_time_len(elapsed_time);
  	len = 6 + elapsed_time_len;
2d0817d11   Arnaldo Carvalho de Melo   [DCCP] options: M...
363
364
  	if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
  		return -1;
7c657876b   Arnaldo Carvalho de Melo   [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   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
371
372
  	memcpy(to, &tstamp_echo, 4);
  	to += 4;
afe00251d   Andrea Bittau   [DCCP]: Initial f...
373

1bc098695   Ian McDonald   [DCCP]: Fix the t...
374
  	if (elapsed_time_len == 2) {
60fe62e78   Andrea Bittau   [DCCP]: sparse en...
375
  		const __be16 var16 = htons((u16)elapsed_time);
1bc098695   Ian McDonald   [DCCP]: Fix the t...
376
377
  		memcpy(to, &var16, 2);
  	} else if (elapsed_time_len == 4) {
60fe62e78   Andrea Bittau   [DCCP]: sparse en...
378
  		const __be32 var32 = htonl(elapsed_time);
1bc098695   Ian McDonald   [DCCP]: Fix the t...
379
380
  		memcpy(to, &var32, 4);
  	}
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
381

2d0817d11   Arnaldo Carvalho de Melo   [DCCP] options: M...
382
  	return 0;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
383
  }
7d8709366   Gerrit Renker   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   Gerrit Renker   dccp ccid-2: Sche...
388
  	struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
b3d14bff1   Gerrit Renker   dccp ccid-2: Impl...
389
  	const u16 buflen = dccp_ackvec_buflen(av);
7d8709366   Gerrit Renker   dccp ccid-2: Sepa...
390
  	/* Figure out how many options do we need to represent the ackvec */
b3d14bff1   Gerrit Renker   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   Gerrit Renker   dccp ccid-2: Sepa...
393
394
395
  	u8 i, nonce = 0;
  	const unsigned char *tail, *from;
  	unsigned char *to;
d83447f09   Gerrit Renker   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   Gerrit Renker   dccp ccid-2: Sepa...
400
  		return -1;
d83447f09   Gerrit Renker   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   Gerrit Renker   dccp ccid-2: Sepa...
417
418
  
  	to   = skb_push(skb, len);
b3d14bff1   Gerrit Renker   dccp ccid-2: Impl...
419
  	len  = buflen;
7d8709366   Gerrit Renker   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   Gerrit Renker   dccp ccid-2: Sche...
457
  	if (dccp_ackvec_update_records(av, dcb->dccpd_seq, nonce))
7d8709366   Gerrit Renker   dccp ccid-2: Sepa...
458
459
460
  		return -ENOBUFS;
  	return 0;
  }
d37105669   Gerrit Renker   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   Gerrit Renker   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   Ben Hutchings   net: Fix (nearly-...
482
   *
8c862c23e   Gerrit Renker   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   Gerrit Renker   dccp ccid-2: Sepa...
490
  {
8c862c23e   Gerrit Renker   dccp: Header opti...
491
  	u8 tot_len, *to;
4829007c7   Gerrit Renker   dccp ccid-2: Sepa...
492

8c862c23e   Gerrit Renker   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   Gerrit Renker   dccp ccid-2: Sepa...
497
  		return -1;
c2f42077b   Gerrit Renker   dccp ccid-2: Sche...
498
  	}
4829007c7   Gerrit Renker   dccp ccid-2: Sepa...
499

8c862c23e   Gerrit Renker   dccp: Header opti...
500
  	if (unlikely(val == NULL || len == 0))
3db1cd5c0   Rusty Russell   net: fix assignme...
501
  		len = repeat_first = false;
8c862c23e   Gerrit Renker   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   Gerrit Renker   dccp ccid-2: Sepa...
510

8c862c23e   Gerrit Renker   dccp: Header opti...
511
  	to    = skb_push(skb, tot_len);
410e27a49   Gerrit Renker   This reverts "Mer...
512
  	*to++ = type;
8c862c23e   Gerrit Renker   dccp: Header opti...
513
  	*to++ = tot_len;
410e27a49   Gerrit Renker   This reverts "Mer...
514
  	*to++ = feat;
4829007c7   Gerrit Renker   dccp ccid-2: Sepa...
515

8c862c23e   Gerrit Renker   dccp: Header opti...
516
517
  	if (repeat_first)
  		*to++ = *val;
410e27a49   Gerrit Renker   This reverts "Mer...
518
519
  	if (len)
  		memcpy(to, val, len);
d0440ee6f   Gerrit Renker   dccp: Support for...
520
521
  	return 0;
  }
af3b867e2   Gerrit Renker   [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   Arnaldo Carvalho de Melo   [DCCP] options: M...
533
  int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
534
535
536
537
  {
  	struct dccp_sock *dp = dccp_sk(sk);
  
  	DCCP_SKB_CB(skb)->dccpd_opt_len = 0;
4098dce5b   Gerrit Renker   dccp: Remove manu...
538
  	if (dp->dccps_send_ndp_count && dccp_insert_option_ndp(sk, skb))
2d0817d11   Arnaldo Carvalho de Melo   [DCCP] options: M...
539
  		return -1;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
540

8b7b6c75c   Gerrit Renker   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   Arnaldo Carvalho de Melo   [DCCP] options: M...
545
  			return -1;
8b7b6c75c   Gerrit Renker   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   Gerrit Renker   dccp: make implem...
550
  			 * This is currently used for TFRC initialisation.
8b7b6c75c   Gerrit Renker   dccp: Integrate f...
551
  			 */
a7d13fbf8   Gerrit Renker   dccp: remove unus...
552
  			if (dccp_insert_option_timestamp(skb))
8b7b6c75c   Gerrit Renker   dccp: Integrate f...
553
  				return -1;
b3d14bff1   Gerrit Renker   dccp ccid-2: Impl...
554
  		} else if (dccp_ackvec_pending(sk) &&
8b7b6c75c   Gerrit Renker   dccp: Integrate f...
555
556
557
  			   dccp_insert_option_ackvec(sk, skb)) {
  				return -1;
  		}
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
558
  	}
507d37cf2   Arnaldo Carvalho de Melo   [CCID] Only call ...
559
  	if (dp->dccps_hc_rx_insert_options) {
2d0817d11   Arnaldo Carvalho de Melo   [DCCP] options: M...
560
561
  		if (ccid_hc_rx_insert_options(dp->dccps_hc_rx_ccid, sk, skb))
  			return -1;
507d37cf2   Arnaldo Carvalho de Melo   [CCID] Only call ...
562
563
  		dp->dccps_hc_rx_insert_options = 0;
  	}
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
564

b4d4f7c70   Gerrit Renker   [DCCP]: Handle ti...
565
566
567
  	if (dp->dccps_timestamp_echo != 0 &&
  	    dccp_insert_option_timestamp_echo(dp, NULL, skb))
  		return -1;
af3b867e2   Gerrit Renker   [DCCP]: Support i...
568
569
570
  	dccp_insert_option_padding(skb);
  	return 0;
  }
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
571

af3b867e2   Gerrit Renker   [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   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
575

8b7b6c75c   Gerrit Renker   dccp: Integrate f...
576
577
  	if (dccp_feat_insert_opts(NULL, dreq, skb))
  		return -1;
59b80802a   Gerrit Renker   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   Gerrit Renker   [DCCP]: Support i...
581
582
583
  	if (dreq->dreq_timestamp_echo != 0 &&
  	    dccp_insert_option_timestamp_echo(NULL, dreq, skb))
  		return -1;
2d0817d11   Arnaldo Carvalho de Melo   [DCCP] options: M...
584

af3b867e2   Gerrit Renker   [DCCP]: Support i...
585
  	dccp_insert_option_padding(skb);
2d0817d11   Arnaldo Carvalho de Melo   [DCCP] options: M...
586
  	return 0;
7c657876b   Arnaldo Carvalho de Melo   [DCCP]: Initial i...
587
  }