1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2012 David Hoeppner. All rights reserved.
14 */
15
16 #include <sys/types.h>
17 #include <sys/stream.h>
18 #include <sys/debug.h>
19 #include <sys/cmn_err.h>
20
21 #include <inet/dccp_impl.h>
22 #include <inet/dccp_stack.h>
23
24 /*
25 * This file contains functions to parse and process DCCP options.
26 */
27
28
29 /*
30 * Parse the options in a DCCP header.
31 */
32 int
33 dccp_parse_options(dccp_t *dccp, dccpha_t *dccpha)
34 {
35 uchar_t *end;
36 uchar_t *up;
37 uint8_t dccp_type;
38 uint32_t option_value;
39 uint8_t option_type;
40 uint8_t option_length;
41 int len;
42 int i;
43 uchar_t *value;
44 boolean_t mandatory = B_FALSE;
45 int error;
46
47 cmn_err(CE_NOTE, "dccp_features.c: dccp_parse_options");
48
49 dccp_type = dccpha->dha_type;
50
51 up = (uchar_t *)dccpha;
52 end = up + DCCP_HDR_LENGTH(dccpha);
53 up += 20;
54
55 while (up != end) {
56 option_length = 0;
57 option_type = *up++;
58
59 if (option_type > 31) {
60 if (up == end) {
61 goto length_error;
62 }
63
64 option_length = *up++;
65 if (option_length < 2) {
66 goto length_error;
67 }
68
69 option_length -= 2;
70 value = up;
71
72 up += option_length;
73
74 /* Ignore options with greater length then header */
75 if (up > end) {
76 goto length_error;
77 }
78 } else {
79 value = up;
80 }
81
82 /* Single byte unknow option */
83 if (option_type >= 3 && option_type <=31) {
84 if (mandatory) {
85 error = DCCP_RESET_MANDATORY_ERROR;
86 } else {
87 error = DCCP_RESET_OPTION_ERROR;
88 }
89
90 dccp->dccp_reset_code = error;
91 /*
92 * this should be correct:
93 * dccp->dccp_reset_data[0] = option_type;
94 * dccp->dccp_reset_data[1] = value[0];
95 *
96 * error in the test suit?
97 */
98 dccp->dccp_reset_data[0] = value[0];
99 dccp->dccp_reset_data[1] = 0;
100 dccp->dccp_reset_data[2] = 0;
101
102 return (-1);
103 }
104
105 if (option_type >= 45 && option_type <=127)
106 break;
107
108
109 switch (option_type) {
110 case DCCP_OPTION_PADDING:
111 cmn_err(CE_NOTE, "PADDING");
112 break;
113 case DCCP_OPTION_MANDATORY:
114 cmn_err(CE_NOTE, "MANDATORY");
115 if (mandatory)
116 goto option_error;
117
118 if (dccp_type != DCCP_PKT_DATA)
119 mandatory = B_TRUE;
120 break;
121 case DCCP_OPTION_SLOW_RECEIVER:
122 cmn_err(CE_NOTE, "SLOW RECEIVER");
123 break;
124 case DCCP_OPTION_CHANGE_L:
125 case DCCP_OPTION_CONFIRM_L:
126 case DCCP_OPTION_CHANGE_R:
127 case DCCP_OPTION_CONFIRM_R:
128 if (dccp_type == DCCP_PACKET_DATA)
129 break;
130
131 if (option_length == 0)
132 goto option_error;
133
134 error = dccp_parse_feature(dccp, option_type, option_length,
135 value, mandatory);
136 if (error != 0)
137 goto feature_error;
138
139 break;
140 case DCCP_OPTION_INIT_COOKIE:
141 cmn_err(CE_NOTE, "INIT COOKIE");
142 break;
143 case DCCP_OPTION_NDP_COUNT:
144 cmn_err(CE_NOTE, "NDP COUNT");
145 if (option_length > 6)
146 goto option_error;
147 break;
148 case DCCP_OPTION_ACK_VECTOR_1:
149 cmn_err(CE_NOTE, "ACK VECTOR 1");
150 break;
151 case DCCP_OPTION_ACK_VECTOR_2:
152 cmn_err(CE_NOTE, "ACK VECTOR 2");
153 break;
154 case DCCP_OPTION_DATA_DROPPED:
155 cmn_err(CE_NOTE, "DATA DROPPED");
156 break;
157 case DCCP_OPTION_TIMESTAMP:
158 cmn_err(CE_NOTE, "TIMESTAMP");
159 if (option_length != 4)
160 goto option_error;
161
162 option_value = BE32_TO_U32(value);
163 if (option_value == 0) {
164 cmn_err(CE_NOTE, "Zero timestamp");
165 break;
166 }
167
168 dccp->dccp_timestamp_echo = ntohs(option_value);
169 dccp->dccp_timestamp = TICK_TO_MSEC(LBOLT_FASTPATH);
170 break;
171 case DCCP_OPTION_TIMESTAMP_ECHO:
172 cmn_err(CE_NOTE, "TIMESTAMP ECHO");
173 if (option_length != 4 && option_length != 6 &&
174 option_length != 8) {
175 goto option_error;
176 }
177
178 option_value = BE32_TO_U32(value);
179
180 option_length -= 4;
181 break;
182 case DCCP_OPTION_ELAPSED_TIME:
183 cmn_err(CE_NOTE, "ELAPSES TIME");
184 switch (option_length) {
185 case 2:
186 break;
187 case 4:
188 break;
189 default:
190 goto option_error;
191 }
192 break;
193 case DCCP_OPTION_DATA_CHECKSUM:
194 cmn_err(CE_NOTE, "DATA CHECKSUM");
195 break;
196
197 default:
198 cmn_err(CE_NOTE, "unknow option");
199 break;
200 }
201
202 if (option_type != DCCP_OPTION_MANDATORY) {
203 mandatory = B_FALSE;
204 }
205 }
206
207 if (mandatory)
208 goto option_error;
209
210 length_error:
211 return (0);
212
213 option_error:
214 if (mandatory) {
215 error = DCCP_RESET_MANDATORY_ERROR;
216 } else {
217 error = DCCP_RESET_OPTION_ERROR;
218 }
219
220 cmn_err(CE_NOTE, "setting error code");
221
222 feature_error:
223 dccp->dccp_reset_code = error;
224 dccp->dccp_reset_data[0] = option_type;
225 dccp->dccp_reset_data[1] = option_length > 0 ? value[0] : 0;
226 dccp->dccp_reset_data[2] = option_length > 1 ? value[1] : 0;
227
228 return (-1);
229 }
230
231 int
232 dccp_process_options(dccp_t *dccp, dccpha_t *dccpha)
233 {
234 int error;
235
236 cmn_err(CE_NOTE, "dccp_features.c: dccp_process_features");
237
238 error = dccp_parse_options(dccp, dccpha);
239
240 return (error);
241 }
242
243 int
244 dccp_generate_options(dccp_t *dccp, void **opt, size_t *opt_len)
245 {
246 dccp_feature_t *feature = NULL;
247 uint8_t buf[1024]; /* XXX */
248 uint8_t option_type;
249 uint_t len = 0;
250 uint_t total_len = 0;
251 void *options = NULL;
252 int rest;
253
254 cmn_err(CE_NOTE, "dccp_features.c: dccp_generate_options");
255
256 for (feature = list_head(&dccp->dccp_features); feature;
257 feature = list_next(&dccp->dccp_features, feature)) {
258 if (feature->df_option == DCCP_OPTION_CHANGE_L) {
259 option_type = DCCP_OPTION_CONFIRM_R;
260 } else {
261 option_type = DCCP_OPTION_CONFIRM_L;
262 }
263 /*
264 if (feature->df_mandatory == B_TRUE) {
265 buf[len] = DCCP_OPTION_MANDATORY;
266 len++;
267 }
268 */
269 if (feature->df_type == DCCP_FEATURE_CCID) {
270 cmn_err(CE_NOTE, "FOUND DCCP_FEATURE_CCID");
271
272 buf[len] = option_type;
273 len++;
274 buf[len] = 4;
275 len++;
276 buf[len] = DCCP_FEATURE_CCID;
277 len++;
278 buf[len] = 2;
279 len++;
280 }
281
282 if (feature->df_type == DCCP_FEATURE_ALLOW_SHORT_SEQNOS) {
283 buf[len] = option_type;
284 len++;
285 buf[len] = 4;
286 len++;
287 buf[len] = feature->df_type;
288 len++;
289 buf[len] = 0;
290 len++;
291 }
292
293 if (feature->df_type == DCCP_FEATURE_ECN_INCAPABLE) {
294 buf[len] = option_type;
295 len++;
296 buf[len] = 4;
297 len++;
298 buf[len] = feature->df_type;
299 len++;
300 buf[len] = 1;
301 len++;
302 }
303 }
304
305 if (dccp->dccp_timestamp_echo != 0) {
306 uint32_t elapsed;
307 int elapsed_length;
308 clock_t now;
309
310 buf[len] = DCCP_OPTION_TIMESTAMP_ECHO;
311 len++;
312 buf[len] = 10;
313 len++;
314
315 now = TICK_TO_MSEC(LBOLT_FASTPATH);
316 elapsed = now - dccp->dccp_timestamp;
317
318
319 dccp->dccp_timestamp_echo = 0;
320 }
321
322 if (len != 0) {
323 total_len = ((len + (4 - 1)) / 4) * 4;
324 options = kmem_zalloc(total_len, KM_SLEEP);
325 if (options == NULL) {
326 cmn_err(CE_NOTE, "kmem_zalloc failed");
327 return (ENOMEM);
328 }
329 memcpy(options, buf, len);
330 }
331
332 *opt = options;
333 *opt_len = len;
334
335 return (0);
336 }