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 #include <inet/dccp_impl.h> 21 #include <inet/dccp_stack.h> 22 23 /* 24 * This file contains functions to parse and process DCCP options. 25 */ 26 27 28 /* 29 * Parse the options in a DCCP header. 30 */ 31 int 32 dccp_parse_options(dccp_t *dccp, dccpha_t *dccpha) 33 { 34 uchar_t *end; 35 uchar_t *up; 36 uint8_t dccp_type; 37 uint32_t option_value; 38 uint8_t option_type; 39 uint8_t option_length; 40 int len; 41 int i; 42 uchar_t *value; 43 boolean_t mandatory = B_FALSE; 44 int error; 45 46 cmn_err(CE_NOTE, "dccp_features.c: dccp_parse_options"); 47 48 dccp_type = dccpha->dha_type; 49 50 up = (uchar_t *)dccpha; 51 end = up + DCCP_HDR_LENGTH(dccpha); 52 up += 20; 53 54 while (up != end) { 55 option_length = 0; 56 option_type = *up++; 57 58 if (option_type > 31) { 59 if (up == end) { 60 goto length_error; 61 } 62 63 option_length = *up++; 64 if (option_length < 2) { 65 goto length_error; 66 } 67 68 option_length -= 2; 69 value = up; 70 71 up += option_length; 72 73 /* Ignore options with greater length then header */ 74 if (up > end) { 75 goto length_error; 76 } 77 } 78 79 switch (option_type) { 80 case DCCP_OPTION_PADDING: 81 cmn_err(CE_NOTE, "PADDING"); 82 break; 83 case DCCP_OPTION_MANDATORY: 84 cmn_err(CE_NOTE, "MANDATORY"); 85 if (mandatory) 86 goto option_error; 87 88 if (dccp_type != DCCP_PKT_DATA) 89 mandatory = B_TRUE; 90 break; 91 case DCCP_OPTION_SLOW_RECEIVER: 92 cmn_err(CE_NOTE, "SLOW RECEIVER"); 93 break; 94 case DCCP_OPTION_CHANGE_L: 95 case DCCP_OPTION_CONFIRM_L: 96 case DCCP_OPTION_CHANGE_R: 97 case DCCP_OPTION_CONFIRM_R: 98 if (dccp_type == DCCP_PKT_DATA) 99 break; 100 101 if (option_length == 0) 102 goto option_error; 103 104 dccp_parse_feature(dccp, option_type, option_length, 105 value, mandatory); 106 break; 107 case DCCP_OPTION_INIT_COOKIE: 108 cmn_err(CE_NOTE, "INIT COOKIE"); 109 break; 110 case DCCP_OPTION_NDP_COUNT: 111 cmn_err(CE_NOTE, "NDP COUNT"); 112 if (option_length > 6) 113 goto option_error; 114 break; 115 case DCCP_OPTION_ACK_VECTOR_1: 116 cmn_err(CE_NOTE, "ACK VECTOR 1"); 117 break; 118 case DCCP_OPTION_ACK_VECTOR_2: 119 cmn_err(CE_NOTE, "ACK VECTOR 2"); 120 break; 121 case DCCP_OPTION_DATA_DROPPED: 122 cmn_err(CE_NOTE, "DATA DROPPED"); 123 break; 124 case DCCP_OPTION_TIMESTAMP: 125 cmn_err(CE_NOTE, "TIMESTAMP"); 126 if (option_length != 4) 127 goto option_error; 128 129 /* XXX read unaligned big endian */ 130 option_value = ((uint8_t)value[0] << 31); 131 if (option_value) { 132 cmn_err(CE_NOTE, "Zero timestamp"); 133 break; 134 } 135 136 dccp->dccp_timestamp_echo = ntohs(option_value); 137 dccp->dccp_timestamp = gethrtime(); 138 break; 139 case DCCP_OPTION_TIMESTAMP_ECHO: 140 cmn_err(CE_NOTE, "TIMESTAMP ECHO"); 141 if (option_length != 4 && 142 option_length != 6 && 143 option_length != 8) { 144 goto option_error; 145 } 146 147 break; 148 case DCCP_OPTION_ELAPSED_TIME: 149 cmn_err(CE_NOTE, "ELAPSES TIME"); 150 switch (option_length) { 151 case 2: 152 break; 153 case 4: 154 break; 155 default: 156 goto option_error; 157 } 158 break; 159 case DCCP_OPTION_DATA_CHECKSUM: 160 cmn_err(CE_NOTE, "DATA CHECKSUM"); 161 break; 162 163 default: 164 cmn_err(CE_NOTE, "DEFAULT"); 165 break; 166 } 167 168 if (option_type != DCCP_OPTION_MANDATORY) { 169 mandatory = B_FALSE; 170 } 171 } 172 173 if (mandatory) 174 goto option_error; 175 176 length_error: 177 return (0); 178 179 option_error: 180 error = DCCP_RESET_OPTION_ERROR; 181 182 cmn_err(CE_NOTE, "setting error code"); 183 184 dccp->dccp_reset_code = error; 185 dccp->dccp_reset_data[0] = option_type; 186 dccp->dccp_reset_data[1] = option_length > 0 ? value[0] : 0; 187 dccp->dccp_reset_data[2] = option_length > 1 ? value[1] : 0; 188 189 return (-1); 190 } 191 192 void 193 dccp_process_options(dccp_t *dccp, dccpha_t *dccpha) 194 { 195 cmn_err(CE_NOTE, "dccp_features.c: dccp_process_features"); 196 197 dccp_parse_options(dccp, dccpha); 198 } 199 200 int 201 dccp_generate_options(dccp_t *dccp, void **opt, size_t *opt_len) 202 { 203 dccp_feature_t *feature = NULL; 204 uint8_t buf[1024]; /* XXX */ 205 uint8_t option_type; 206 uint_t len = 0; 207 uint_t total_len; 208 void *options; 209 int rest; 210 211 cmn_err(CE_NOTE, "dccp_features.c: dccp_generate_options"); 212 213 for (feature = list_head(&dccp->dccp_features); feature; 214 feature = list_next(&dccp->dccp_features, feature)) { 215 if (feature->df_option == DCCP_OPTION_CHANGE_L) { 216 option_type = DCCP_OPTION_CONFIRM_R; 217 } else { 218 option_type = DCCP_OPTION_CONFIRM_L; 219 } 220 /* 221 if (feature->df_mandatory == B_TRUE) { 222 buf[len] = DCCP_OPTION_MANDATORY; 223 len++; 224 } 225 */ 226 if (feature->df_type == DCCP_FEATURE_CCID) { 227 cmn_err(CE_NOTE, "FOUND DCCP_FEATURE_CCID"); 228 229 buf[len] = option_type; 230 len++; 231 buf[len] = 4; 232 len++; 233 buf[len] = DCCP_FEATURE_CCID; 234 len++; 235 buf[len] = 2; 236 len++; 237 } 238 239 if (feature->df_type == DCCP_FEATURE_ALLOW_SHORT_SEQNOS) { 240 buf[len] = option_type; 241 len++; 242 buf[len] = 4; 243 len++; 244 buf[len] = feature->df_type; 245 len++; 246 buf[len] = 0; 247 len++; 248 } 249 250 if (feature->df_type == DCCP_FEATURE_ECN_INCAPABLE) { 251 buf[len] = option_type; 252 len++; 253 buf[len] = 4; 254 len++; 255 buf[len] = feature->df_type; 256 len++; 257 buf[len] = 1; 258 len++; 259 } 260 } 261 262 if (dccp->dccp_timestamp_echo != 0) { 263 uint32_t elapsed; 264 int elapsed_length; 265 266 buf[len] = DCCP_OPTION_TIMESTAMP_ECHO; 267 len++; 268 269 elapsed = gethrtime() - dccp->dccp_timestamp; 270 271 dccp->dccp_timestamp_echo = 0; 272 } 273 274 total_len = ((len + (4 - 1)) / 4) * 4; 275 options = kmem_zalloc(total_len, KM_SLEEP); 276 if (options == NULL) { 277 cmn_err(CE_NOTE, "kmem_zalloc failed"); 278 return (ENOMEM); 279 } 280 memcpy(options, buf, len); 281 282 *opt = options; 283 *opt_len = len; 284 285 return (0); 286 }