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 }
79
80 switch (option_type) {
81 case DCCP_OPTION_PADDING:
82 cmn_err(CE_NOTE, "PADDING");
83 break;
84 case DCCP_OPTION_MANDATORY:
85 cmn_err(CE_NOTE, "MANDATORY");
86 if (mandatory)
87 goto option_error;
88
89 if (dccp_type != DCCP_PKT_DATA)
90 mandatory = B_TRUE;
91 break;
92 case DCCP_OPTION_SLOW_RECEIVER:
93 cmn_err(CE_NOTE, "SLOW RECEIVER");
94 break;
95 case DCCP_OPTION_CHANGE_L:
96 case DCCP_OPTION_CONFIRM_L:
97 case DCCP_OPTION_CHANGE_R:
98 case DCCP_OPTION_CONFIRM_R:
99 if (dccp_type == DCCP_PKT_DATA)
100 break;
101
102 if (option_length == 0)
103 goto option_error;
104
105 dccp_parse_feature(dccp, option_type, option_length,
106 value, mandatory);
107 break;
108 case DCCP_OPTION_INIT_COOKIE:
109 cmn_err(CE_NOTE, "INIT COOKIE");
110 break;
111 case DCCP_OPTION_NDP_COUNT:
112 cmn_err(CE_NOTE, "NDP COUNT");
113 if (option_length > 6)
114 goto option_error;
115 break;
116 case DCCP_OPTION_ACK_VECTOR_1:
117 cmn_err(CE_NOTE, "ACK VECTOR 1");
118 break;
119 case DCCP_OPTION_ACK_VECTOR_2:
120 cmn_err(CE_NOTE, "ACK VECTOR 2");
121 break;
122 case DCCP_OPTION_DATA_DROPPED:
123 cmn_err(CE_NOTE, "DATA DROPPED");
124 break;
125 case DCCP_OPTION_TIMESTAMP:
126 cmn_err(CE_NOTE, "TIMESTAMP");
127 if (option_length != 4)
128 goto option_error;
129
130 /* XXX read unaligned big endian */
131 option_value = ((uint8_t)value[0] << 24);
132 option_value += ((uint8_t)value[1] << 16);
133 option_value += ((uint8_t)value[2] << 8);
134 option_value += (uint8_t)value[3];
135 if (option_value) {
136 cmn_err(CE_NOTE, "Zero timestamp");
137 break;
138 }
139
140 dccp->dccp_timestamp_echo = ntohs(option_value);
141 dccp->dccp_timestamp = TICK_TO_MSEC(LBOLT_FASTPATH);
142 break;
143 case DCCP_OPTION_TIMESTAMP_ECHO:
144 cmn_err(CE_NOTE, "TIMESTAMP ECHO");
145 if (option_length != 4 &&
146 option_length != 6 &&
147 option_length != 8) {
148 goto option_error;
149 }
150
151 break;
152 case DCCP_OPTION_ELAPSED_TIME:
153 cmn_err(CE_NOTE, "ELAPSES TIME");
154 switch (option_length) {
155 case 2:
156 break;
157 case 4:
158 break;
159 default:
160 goto option_error;
161 }
162 break;
163 case DCCP_OPTION_DATA_CHECKSUM:
164 cmn_err(CE_NOTE, "DATA CHECKSUM");
165 break;
166
167 default:
168 cmn_err(CE_NOTE, "DEFAULT");
169 break;
170 }
171
172 if (option_type != DCCP_OPTION_MANDATORY) {
173 mandatory = B_FALSE;
174 }
175 }
176
177 if (mandatory)
178 goto option_error;
179
180 length_error:
181 return (0);
182
183 option_error:
184 error = DCCP_RESET_OPTION_ERROR;
185
186 cmn_err(CE_NOTE, "setting error code");
187
188 dccp->dccp_reset_code = error;
189 dccp->dccp_reset_data[0] = option_type;
190 dccp->dccp_reset_data[1] = option_length > 0 ? value[0] : 0;
191 dccp->dccp_reset_data[2] = option_length > 1 ? value[1] : 0;
192
193 return (-1);
194 }
195
196 void
197 dccp_process_options(dccp_t *dccp, dccpha_t *dccpha)
198 {
199 cmn_err(CE_NOTE, "dccp_features.c: dccp_process_features");
200
201 dccp_parse_options(dccp, dccpha);
202 }
203
204 int
205 dccp_generate_options(dccp_t *dccp, void **opt, size_t *opt_len)
206 {
207 dccp_feature_t *feature = NULL;
208 uint8_t buf[1024]; /* XXX */
209 uint8_t option_type;
210 uint_t len = 0;
211 uint_t total_len;
212 void *options;
213 int rest;
214
215 cmn_err(CE_NOTE, "dccp_features.c: dccp_generate_options");
216
217 for (feature = list_head(&dccp->dccp_features); feature;
218 feature = list_next(&dccp->dccp_features, feature)) {
219 if (feature->df_option == DCCP_OPTION_CHANGE_L) {
220 option_type = DCCP_OPTION_CONFIRM_R;
221 } else {
222 option_type = DCCP_OPTION_CONFIRM_L;
223 }
224 /*
225 if (feature->df_mandatory == B_TRUE) {
226 buf[len] = DCCP_OPTION_MANDATORY;
227 len++;
228 }
229 */
230 if (feature->df_type == DCCP_FEATURE_CCID) {
231 cmn_err(CE_NOTE, "FOUND DCCP_FEATURE_CCID");
232
233 buf[len] = option_type;
234 len++;
235 buf[len] = 4;
236 len++;
237 buf[len] = DCCP_FEATURE_CCID;
238 len++;
239 buf[len] = 2;
240 len++;
241 }
242
243 if (feature->df_type == DCCP_FEATURE_ALLOW_SHORT_SEQNOS) {
244 buf[len] = option_type;
245 len++;
246 buf[len] = 4;
247 len++;
248 buf[len] = feature->df_type;
249 len++;
250 buf[len] = 0;
251 len++;
252 }
253
254 if (feature->df_type == DCCP_FEATURE_ECN_INCAPABLE) {
255 buf[len] = option_type;
256 len++;
257 buf[len] = 4;
258 len++;
259 buf[len] = feature->df_type;
260 len++;
261 buf[len] = 1;
262 len++;
263 }
264 }
265
266 if (dccp->dccp_timestamp_echo != 0) {
267 uint32_t elapsed;
268 int elapsed_length;
269 clock_t now;
270
271 buf[len] = DCCP_OPTION_TIMESTAMP_ECHO;
272 len++;
273 buf[len] = 10;
274 len++;
275
276 now = TICK_TO_MSEC(LBOLT_FASTPATH);
277 elapsed = now - dccp->dccp_timestamp;
278
279
280 dccp->dccp_timestamp_echo = 0;
281 }
282
283 total_len = ((len + (4 - 1)) / 4) * 4;
284 options = kmem_zalloc(total_len, KM_SLEEP);
285 if (options == NULL) {
286 cmn_err(CE_NOTE, "kmem_zalloc failed");
287 return (ENOMEM);
288 }
289 memcpy(options, buf, len);
290
291 *opt = options;
292 *opt_len = len;
293
294 return (0);
295 }