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 }