1 /* 2 * net/dccp/options.c 3 * 4 * An implementation of the DCCP protocol 5 * Copyright (c) 2005 Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> 6 * Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@ghostprotocols.net> 7 * Copyright (c) 2005 Ian McDonald <iam4@cs.waikato.ac.nz> 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License 11 * as published by the Free Software Foundation; either version 12 * 2 of the License, or (at your option) any later version. 13 */ 14 #include <linux/config.h> 15 #include <linux/dccp.h> 16 #include <linux/module.h> 17 #include <linux/types.h> 18 #include <linux/kernel.h> 19 #include <linux/skbuff.h> 20 21 #include "ackvec.h" 22 #include "ccid.h" 23 #include "dccp.h" 24 25 /* stores the default values for new connection. may be changed with sysctl */ 26 static const struct dccp_options dccpo_default_values = { 27 .dccpo_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW, 28 .dccpo_rx_ccid = DCCPF_INITIAL_CCID, 29 .dccpo_tx_ccid = DCCPF_INITIAL_CCID, 30 .dccpo_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR, 31 .dccpo_send_ndp_count = DCCPF_INITIAL_SEND_NDP_COUNT, 32 }; 33 34 void dccp_options_init(struct dccp_options *dccpo) 35 { 36 memcpy(dccpo, &dccpo_default_values, sizeof(*dccpo)); 37 } 38 39 static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len) 40 { 41 u32 value = 0; 42 43 if (len > 3) 44 value += *bf++ << 24; 45 if (len > 2) 46 value += *bf++ << 16; 47 if (len > 1) 48 value += *bf++ << 8; 49 if (len > 0) 50 value += *bf; 51 52 return value; 53 } 54 55 int dccp_parse_options(struct sock *sk, struct sk_buff *skb) 56 { 57 struct dccp_sock *dp = dccp_sk(sk); 58 #ifdef CONFIG_IP_DCCP_DEBUG 59 const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? 60 "CLIENT rx opt: " : "server rx opt: "; 61 #endif 62 const struct dccp_hdr *dh = dccp_hdr(skb); 63 const u8 pkt_type = DCCP_SKB_CB(skb)->dccpd_type; 64 unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb); 65 unsigned char *opt_ptr = options; 66 const unsigned char *opt_end = (unsigned char *)dh + 67 (dh->dccph_doff * 4); 68 struct dccp_options_received *opt_recv = &dp->dccps_options_received; 69 unsigned char opt, len; 70 unsigned char *value; 71 u32 elapsed_time; 72 73 memset(opt_recv, 0, sizeof(*opt_recv)); 74 75 while (opt_ptr != opt_end) { 76 opt = *opt_ptr++; 77 len = 0; 78 value = NULL; 79 80 /* Check if this isn't a single byte option */ 81 if (opt > DCCPO_MAX_RESERVED) { 82 if (opt_ptr == opt_end) 83 goto out_invalid_option; 84 85 len = *opt_ptr++; 86 if (len < 3) 87 goto out_invalid_option; 88 /* 89 * Remove the type and len fields, leaving 90 * just the value size 91 */ 92 len -= 2; 93 value = opt_ptr; 94 opt_ptr += len; 95 96 if (opt_ptr > opt_end) 97 goto out_invalid_option; 98 } 99 100 switch (opt) { 101 case DCCPO_PADDING: 102 break; 103 case DCCPO_NDP_COUNT: 104 if (len > 3) 105 goto out_invalid_option; 106 107 opt_recv->dccpor_ndp = dccp_decode_value_var(value, len); 108 dccp_pr_debug("%sNDP count=%d\n", debug_prefix, 109 opt_recv->dccpor_ndp); 110 break; 111 case DCCPO_ACK_VECTOR_0: 112 case DCCPO_ACK_VECTOR_1: 113 if (pkt_type == DCCP_PKT_DATA) 114 continue; 115 116 if (dp->dccps_options.dccpo_send_ack_vector && 117 dccp_ackvec_parse(sk, skb, opt, value, len)) 118 goto out_invalid_option; 119 break; 120 case DCCPO_TIMESTAMP: 121 if (len != 4) 122 goto out_invalid_option; 123 124 opt_recv->dccpor_timestamp = ntohl(*(u32 *)value); 125 126 dp->dccps_timestamp_echo = opt_recv->dccpor_timestamp; 127 dccp_timestamp(sk, &dp->dccps_timestamp_time); 128 129 dccp_pr_debug("%sTIMESTAMP=%u, ackno=%llu\n", 130 debug_prefix, opt_recv->dccpor_timestamp, 131 (unsigned long long) 132 DCCP_SKB_CB(skb)->dccpd_ack_seq); 133 break; 134 case DCCPO_TIMESTAMP_ECHO: 135 if (len != 4 && len != 6 && len != 8) 136 goto out_invalid_option; 137 138 opt_recv->dccpor_timestamp_echo = ntohl(*(u32 *)value); 139 140 dccp_pr_debug("%sTIMESTAMP_ECHO=%u, len=%d, ackno=%llu, ", 141 debug_prefix, 142 opt_recv->dccpor_timestamp_echo, 143 len + 2, 144 (unsigned long long) 145 DCCP_SKB_CB(skb)->dccpd_ack_seq); 146 147 148 if (len == 4) 149 break; 150 151 if (len == 6) 152 elapsed_time = ntohs(*(u16 *)(value + 4)); 153 else 154 elapsed_time = ntohl(*(u32 *)(value + 4)); 155 156 /* Give precedence to the biggest ELAPSED_TIME */ 157 if (elapsed_time > opt_recv->dccpor_elapsed_time) 158 opt_recv->dccpor_elapsed_time = elapsed_time; 159 break; 160 case DCCPO_ELAPSED_TIME: 161 if (len != 2 && len != 4) 162 goto out_invalid_option; 163 164 if (pkt_type == DCCP_PKT_DATA) 165 continue; 166 167 if (len == 2) 168 elapsed_time = ntohs(*(u16 *)value); 169 else 170 elapsed_time = ntohl(*(u32 *)value); 171 172 if (elapsed_time > opt_recv->dccpor_elapsed_time) 173 opt_recv->dccpor_elapsed_time = elapsed_time; 174 175 dccp_pr_debug("%sELAPSED_TIME=%d\n", debug_prefix, 176 elapsed_time); 177 break; 178 /* 179 * From draft-ietf-dccp-spec-11.txt: 180 * 181 * Option numbers 128 through 191 are for 182 * options sent from the HC-Sender to the 183 * HC-Receiver; option numbers 192 through 255 184 * are for options sent from the HC-Receiver to 185 * the HC-Sender. 186 */ 187 case 128 ... 191: { 188 const u16 idx = value - options; 189 190 if (ccid_hc_rx_parse_options(dp->dccps_hc_rx_ccid, sk, 191 opt, len, idx, 192 value) != 0) 193 goto out_invalid_option; 194 } 195 break; 196 case 192 ... 255: { 197 const u16 idx = value - options; 198 199 if (ccid_hc_tx_parse_options(dp->dccps_hc_tx_ccid, sk, 200 opt, len, idx, 201 value) != 0) 202 goto out_invalid_option; 203 } 204 break; 205 default: 206 pr_info("DCCP(%p): option %d(len=%d) not " 207 "implemented, ignoring\n", 208 sk, opt, len); 209 break; 210 } 211 } 212 213 return 0; 214 215 out_invalid_option: 216 DCCP_INC_STATS_BH(DCCP_MIB_INVALIDOPT); 217 DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_OPTION_ERROR; 218 pr_info("DCCP(%p): invalid option %d, len=%d\n", sk, opt, len); 219 return -1; 220 } 221 222 static void dccp_encode_value_var(const u32 value, unsigned char *to, 223 const unsigned int len) 224 { 225 if (len > 3) 226 *to++ = (value & 0xFF000000) >> 24; 227 if (len > 2) 228 *to++ = (value & 0xFF0000) >> 16; 229 if (len > 1) 230 *to++ = (value & 0xFF00) >> 8; 231 if (len > 0) 232 *to++ = (value & 0xFF); 233 } 234 235 static inline int dccp_ndp_len(const int ndp) 236 { 237 return likely(ndp <= 0xFF) ? 1 : ndp <= 0xFFFF ? 2 : 3; 238 } 239 240 void dccp_insert_option(struct sock *sk, struct sk_buff *skb, 241 const unsigned char option, 242 const void *value, const unsigned char len) 243 { 244 unsigned char *to; 245 246 if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 2 > DCCP_MAX_OPT_LEN) { 247 LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to insert " 248 "%d option!\n", option); 249 return; 250 } 251 252 DCCP_SKB_CB(skb)->dccpd_opt_len += len + 2; 253 254 to = skb_push(skb, len + 2); 255 *to++ = option; 256 *to++ = len + 2; 257 258 memcpy(to, value, len); 259 } 260 261 EXPORT_SYMBOL_GPL(dccp_insert_option); 262 263 static void dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb) 264 { 265 struct dccp_sock *dp = dccp_sk(sk); 266 int ndp = dp->dccps_ndp_count; 267 268 if (dccp_non_data_packet(skb)) 269 ++dp->dccps_ndp_count; 270 else 271 dp->dccps_ndp_count = 0; 272 273 if (ndp > 0) { 274 unsigned char *ptr; 275 const int ndp_len = dccp_ndp_len(ndp); 276 const int len = ndp_len + 2; 277 278 if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) 279 return; 280 281 DCCP_SKB_CB(skb)->dccpd_opt_len += len; 282 283 ptr = skb_push(skb, len); 284 *ptr++ = DCCPO_NDP_COUNT; 285 *ptr++ = len; 286 dccp_encode_value_var(ndp, ptr, ndp_len); 287 } 288 } 289 290 static inline int dccp_elapsed_time_len(const u32 elapsed_time) 291 { 292 return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4; 293 } 294 295 void dccp_insert_option_elapsed_time(struct sock *sk, 296 struct sk_buff *skb, 297 u32 elapsed_time) 298 { 299 #ifdef CONFIG_IP_DCCP_DEBUG 300 struct dccp_sock *dp = dccp_sk(sk); 301 const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? 302 "CLIENT TX opt: " : "server TX opt: "; 303 #endif 304 const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time); 305 const int len = 2 + elapsed_time_len; 306 unsigned char *to; 307 308 if (elapsed_time_len == 0) 309 return; 310 311 if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) { 312 LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to " 313 "insert elapsed time!\n"); 314 return; 315 } 316 317 DCCP_SKB_CB(skb)->dccpd_opt_len += len; 318 319 to = skb_push(skb, len); 320 *to++ = DCCPO_ELAPSED_TIME; 321 *to++ = len; 322 323 if (elapsed_time_len == 2) { 324 const u16 var16 = htons((u16)elapsed_time); 325 memcpy(to, &var16, 2); 326 } else { 327 const u32 var32 = htonl(elapsed_time); 328 memcpy(to, &var32, 4); 329 } 330 331 dccp_pr_debug("%sELAPSED_TIME=%u, len=%d, seqno=%llu\n", 332 debug_prefix, elapsed_time, 333 len, 334 (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq); 335 } 336 337 EXPORT_SYMBOL_GPL(dccp_insert_option_elapsed_time); 338 339 void dccp_timestamp(const struct sock *sk, struct timeval *tv) 340 { 341 const struct dccp_sock *dp = dccp_sk(sk); 342 343 do_gettimeofday(tv); 344 tv->tv_sec -= dp->dccps_epoch.tv_sec; 345 tv->tv_usec -= dp->dccps_epoch.tv_usec; 346 347 while (tv->tv_usec < 0) { 348 tv->tv_sec--; 349 tv->tv_usec += USEC_PER_SEC; 350 } 351 } 352 353 EXPORT_SYMBOL_GPL(dccp_timestamp); 354 355 void dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb) 356 { 357 struct timeval tv; 358 u32 now; 359 360 dccp_timestamp(sk, &tv); 361 now = timeval_usecs(&tv) / 10; 362 /* yes this will overflow but that is the point as we want a 363 * 10 usec 32 bit timer which mean it wraps every 11.9 hours */ 364 365 now = htonl(now); 366 dccp_insert_option(sk, skb, DCCPO_TIMESTAMP, &now, sizeof(now)); 367 } 368 369 EXPORT_SYMBOL_GPL(dccp_insert_option_timestamp); 370 371 static void dccp_insert_option_timestamp_echo(struct sock *sk, 372 struct sk_buff *skb) 373 { 374 struct dccp_sock *dp = dccp_sk(sk); 375 #ifdef CONFIG_IP_DCCP_DEBUG 376 const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? 377 "CLIENT TX opt: " : "server TX opt: "; 378 #endif 379 struct timeval now; 380 u32 tstamp_echo; 381 u32 elapsed_time; 382 int len, elapsed_time_len; 383 unsigned char *to; 384 385 dccp_timestamp(sk, &now); 386 elapsed_time = timeval_delta(&now, &dp->dccps_timestamp_time) / 10; 387 elapsed_time_len = dccp_elapsed_time_len(elapsed_time); 388 len = 6 + elapsed_time_len; 389 390 if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) { 391 LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to insert " 392 "timestamp echo!\n"); 393 return; 394 } 395 396 DCCP_SKB_CB(skb)->dccpd_opt_len += len; 397 398 to = skb_push(skb, len); 399 *to++ = DCCPO_TIMESTAMP_ECHO; 400 *to++ = len; 401 402 tstamp_echo = htonl(dp->dccps_timestamp_echo); 403 memcpy(to, &tstamp_echo, 4); 404 to += 4; 405 406 if (elapsed_time_len == 2) { 407 const u16 var16 = htons((u16)elapsed_time); 408 memcpy(to, &var16, 2); 409 } else if (elapsed_time_len == 4) { 410 const u32 var32 = htonl(elapsed_time); 411 memcpy(to, &var32, 4); 412 } 413 414 dccp_pr_debug("%sTIMESTAMP_ECHO=%u, len=%d, seqno=%llu\n", 415 debug_prefix, dp->dccps_timestamp_echo, 416 len, 417 (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq); 418 419 dp->dccps_timestamp_echo = 0; 420 dp->dccps_timestamp_time.tv_sec = 0; 421 dp->dccps_timestamp_time.tv_usec = 0; 422 } 423 424 void dccp_insert_options(struct sock *sk, struct sk_buff *skb) 425 { 426 struct dccp_sock *dp = dccp_sk(sk); 427 428 DCCP_SKB_CB(skb)->dccpd_opt_len = 0; 429 430 if (dp->dccps_options.dccpo_send_ndp_count) 431 dccp_insert_option_ndp(sk, skb); 432 433 if (!dccp_packet_without_ack(skb)) { 434 if (dp->dccps_options.dccpo_send_ack_vector && 435 dccp_ackvec_pending(dp->dccps_hc_rx_ackvec)) 436 dccp_insert_option_ackvec(sk, skb); 437 if (dp->dccps_timestamp_echo != 0) 438 dccp_insert_option_timestamp_echo(sk, skb); 439 } 440 441 if (dp->dccps_hc_rx_insert_options) { 442 ccid_hc_rx_insert_options(dp->dccps_hc_rx_ccid, sk, skb); 443 dp->dccps_hc_rx_insert_options = 0; 444 } 445 if (dp->dccps_hc_tx_insert_options) { 446 ccid_hc_tx_insert_options(dp->dccps_hc_tx_ccid, sk, skb); 447 dp->dccps_hc_tx_insert_options = 0; 448 } 449 450 /* XXX: insert other options when appropriate */ 451 452 if (DCCP_SKB_CB(skb)->dccpd_opt_len != 0) { 453 /* The length of all options has to be a multiple of 4 */ 454 int padding = DCCP_SKB_CB(skb)->dccpd_opt_len % 4; 455 456 if (padding != 0) { 457 padding = 4 - padding; 458 memset(skb_push(skb, padding), 0, padding); 459 DCCP_SKB_CB(skb)->dccpd_opt_len += padding; 460 } 461 } 462 } 463