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 }