linux/net/dccp/options.c
<<
>>
Prefs
   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 <ian.mcdonald@jandi.co.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/dccp.h>
  15#include <linux/module.h>
  16#include <linux/types.h>
  17#include <asm/unaligned.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#include "feat.h"
  25
  26u64 dccp_decode_value_var(const u8 *bf, const u8 len)
  27{
  28        u64 value = 0;
  29
  30        if (len >= DCCP_OPTVAL_MAXLEN)
  31                value += ((u64)*bf++) << 40;
  32        if (len > 4)
  33                value += ((u64)*bf++) << 32;
  34        if (len > 3)
  35                value += ((u64)*bf++) << 24;
  36        if (len > 2)
  37                value += ((u64)*bf++) << 16;
  38        if (len > 1)
  39                value += ((u64)*bf++) << 8;
  40        if (len > 0)
  41                value += *bf;
  42
  43        return value;
  44}
  45
  46/**
  47 * dccp_parse_options  -  Parse DCCP options present in @skb
  48 * @sk: client|server|listening dccp socket (when @dreq != NULL)
  49 * @dreq: request socket to use during connection setup, or NULL
  50 */
  51int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
  52                       struct sk_buff *skb)
  53{
  54        struct dccp_sock *dp = dccp_sk(sk);
  55        const struct dccp_hdr *dh = dccp_hdr(skb);
  56        const u8 pkt_type = DCCP_SKB_CB(skb)->dccpd_type;
  57        u64 ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq;
  58        unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb);
  59        unsigned char *opt_ptr = options;
  60        const unsigned char *opt_end = (unsigned char *)dh +
  61                                        (dh->dccph_doff * 4);
  62        struct dccp_options_received *opt_recv = &dp->dccps_options_received;
  63        unsigned char opt, len;
  64        unsigned char *uninitialized_var(value);
  65        u32 elapsed_time;
  66        __be32 opt_val;
  67        int rc;
  68        int mandatory = 0;
  69
  70        memset(opt_recv, 0, sizeof(*opt_recv));
  71
  72        opt = len = 0;
  73        while (opt_ptr != opt_end) {
  74                opt   = *opt_ptr++;
  75                len   = 0;
  76                value = NULL;
  77
  78                /* Check if this isn't a single byte option */
  79                if (opt > DCCPO_MAX_RESERVED) {
  80                        if (opt_ptr == opt_end)
  81                                goto out_nonsensical_length;
  82
  83                        len = *opt_ptr++;
  84                        if (len < 2)
  85                                goto out_nonsensical_length;
  86                        /*
  87                         * Remove the type and len fields, leaving
  88                         * just the value size
  89                         */
  90                        len     -= 2;
  91                        value   = opt_ptr;
  92                        opt_ptr += len;
  93
  94                        if (opt_ptr > opt_end)
  95                                goto out_nonsensical_length;
  96                }
  97
  98                /*
  99                 * CCID-Specific Options (from RFC 4340, sec. 10.3):
 100                 *
 101                 * Option numbers 128 through 191 are for options sent from the
 102                 * HC-Sender to the HC-Receiver; option numbers 192 through 255
 103                 * are for options sent from the HC-Receiver to the HC-Sender.
 104                 *
 105                 * CCID-specific options are ignored during connection setup, as
 106                 * negotiation may still be in progress (see RFC 4340, 10.3).
 107                 * The same applies to Ack Vectors, as these depend on the CCID.
 108                 *
 109                 */
 110                if (dreq != NULL && (opt >= 128 ||
 111                    opt == DCCPO_ACK_VECTOR_0 || opt == DCCPO_ACK_VECTOR_1))
 112                        goto ignore_option;
 113
 114                switch (opt) {
 115                case DCCPO_PADDING:
 116                        break;
 117                case DCCPO_MANDATORY:
 118                        if (mandatory)
 119                                goto out_invalid_option;
 120                        if (pkt_type != DCCP_PKT_DATA)
 121                                mandatory = 1;
 122                        break;
 123                case DCCPO_NDP_COUNT:
 124                        if (len > 6)
 125                                goto out_invalid_option;
 126
 127                        opt_recv->dccpor_ndp = dccp_decode_value_var(value, len);
 128                        dccp_pr_debug("%s opt: NDP count=%llu\n", dccp_role(sk),
 129                                      (unsigned long long)opt_recv->dccpor_ndp);
 130                        break;
 131                case DCCPO_CHANGE_L ... DCCPO_CONFIRM_R:
 132                        if (pkt_type == DCCP_PKT_DATA)      /* RFC 4340, 6 */
 133                                break;
 134                        rc = dccp_feat_parse_options(sk, dreq, mandatory, opt,
 135                                                    *value, value + 1, len - 1);
 136                        if (rc)
 137                                goto out_featneg_failed;
 138                        break;
 139                case DCCPO_ACK_VECTOR_0:
 140                case DCCPO_ACK_VECTOR_1:
 141                        if (dccp_packet_without_ack(skb))   /* RFC 4340, 11.4 */
 142                                break;
 143                        if (dp->dccps_hc_rx_ackvec != NULL &&
 144                            dccp_ackvec_parse(sk, skb, &ackno, opt, value, len))
 145                                goto out_invalid_option;
 146                        break;
 147                case DCCPO_TIMESTAMP:
 148                        if (len != 4)
 149                                goto out_invalid_option;
 150                        /*
 151                         * RFC 4340 13.1: "The precise time corresponding to
 152                         * Timestamp Value zero is not specified". We use
 153                         * zero to indicate absence of a meaningful timestamp.
 154                         */
 155                        opt_val = get_unaligned((__be32 *)value);
 156                        if (unlikely(opt_val == 0)) {
 157                                DCCP_WARN("Timestamp with zero value\n");
 158                                break;
 159                        }
 160
 161                        if (dreq != NULL) {
 162                                dreq->dreq_timestamp_echo = ntohl(opt_val);
 163                                dreq->dreq_timestamp_time = dccp_timestamp();
 164                        } else {
 165                                opt_recv->dccpor_timestamp =
 166                                        dp->dccps_timestamp_echo = ntohl(opt_val);
 167                                dp->dccps_timestamp_time = dccp_timestamp();
 168                        }
 169                        dccp_pr_debug("%s rx opt: TIMESTAMP=%u, ackno=%llu\n",
 170                                      dccp_role(sk), ntohl(opt_val),
 171                                      (unsigned long long)
 172                                      DCCP_SKB_CB(skb)->dccpd_ack_seq);
 173                        break;
 174                case DCCPO_TIMESTAMP_ECHO:
 175                        if (len != 4 && len != 6 && len != 8)
 176                                goto out_invalid_option;
 177
 178                        opt_val = get_unaligned((__be32 *)value);
 179                        opt_recv->dccpor_timestamp_echo = ntohl(opt_val);
 180
 181                        dccp_pr_debug("%s rx opt: TIMESTAMP_ECHO=%u, len=%d, "
 182                                      "ackno=%llu", dccp_role(sk),
 183                                      opt_recv->dccpor_timestamp_echo,
 184                                      len + 2,
 185                                      (unsigned long long)
 186                                      DCCP_SKB_CB(skb)->dccpd_ack_seq);
 187
 188                        value += 4;
 189
 190                        if (len == 4) {         /* no elapsed time included */
 191                                dccp_pr_debug_cat("\n");
 192                                break;
 193                        }
 194
 195                        if (len == 6) {         /* 2-byte elapsed time */
 196                                __be16 opt_val2 = get_unaligned((__be16 *)value);
 197                                elapsed_time = ntohs(opt_val2);
 198                        } else {                /* 4-byte elapsed time */
 199                                opt_val = get_unaligned((__be32 *)value);
 200                                elapsed_time = ntohl(opt_val);
 201                        }
 202
 203                        dccp_pr_debug_cat(", ELAPSED_TIME=%u\n", elapsed_time);
 204
 205                        /* Give precedence to the biggest ELAPSED_TIME */
 206                        if (elapsed_time > opt_recv->dccpor_elapsed_time)
 207                                opt_recv->dccpor_elapsed_time = elapsed_time;
 208                        break;
 209                case DCCPO_ELAPSED_TIME:
 210                        if (dccp_packet_without_ack(skb))   /* RFC 4340, 13.2 */
 211                                break;
 212
 213                        if (len == 2) {
 214                                __be16 opt_val2 = get_unaligned((__be16 *)value);
 215                                elapsed_time = ntohs(opt_val2);
 216                        } else if (len == 4) {
 217                                opt_val = get_unaligned((__be32 *)value);
 218                                elapsed_time = ntohl(opt_val);
 219                        } else {
 220                                goto out_invalid_option;
 221                        }
 222
 223                        if (elapsed_time > opt_recv->dccpor_elapsed_time)
 224                                opt_recv->dccpor_elapsed_time = elapsed_time;
 225
 226                        dccp_pr_debug("%s rx opt: ELAPSED_TIME=%d\n",
 227                                      dccp_role(sk), elapsed_time);
 228                        break;
 229                case 128 ... 191: {
 230                        const u16 idx = value - options;
 231
 232                        if (ccid_hc_rx_parse_options(dp->dccps_hc_rx_ccid, sk,
 233                                                     opt, len, idx,
 234                                                     value) != 0)
 235                                goto out_invalid_option;
 236                }
 237                        break;
 238                case 192 ... 255: {
 239                        const u16 idx = value - options;
 240
 241                        if (ccid_hc_tx_parse_options(dp->dccps_hc_tx_ccid, sk,
 242                                                     opt, len, idx,
 243                                                     value) != 0)
 244                                goto out_invalid_option;
 245                }
 246                        break;
 247                default:
 248                        DCCP_CRIT("DCCP(%p): option %d(len=%d) not "
 249                                  "implemented, ignoring", sk, opt, len);
 250                        break;
 251                }
 252ignore_option:
 253                if (opt != DCCPO_MANDATORY)
 254                        mandatory = 0;
 255        }
 256
 257        /* mandatory was the last byte in option list -> reset connection */
 258        if (mandatory)
 259                goto out_invalid_option;
 260
 261out_nonsensical_length:
 262        /* RFC 4340, 5.8: ignore option and all remaining option space */
 263        return 0;
 264
 265out_invalid_option:
 266        DCCP_INC_STATS_BH(DCCP_MIB_INVALIDOPT);
 267        rc = DCCP_RESET_CODE_OPTION_ERROR;
 268out_featneg_failed:
 269        DCCP_WARN("DCCP(%p): Option %d (len=%d) error=%u\n", sk, opt, len, rc);
 270        DCCP_SKB_CB(skb)->dccpd_reset_code = rc;
 271        DCCP_SKB_CB(skb)->dccpd_reset_data[0] = opt;
 272        DCCP_SKB_CB(skb)->dccpd_reset_data[1] = len > 0 ? value[0] : 0;
 273        DCCP_SKB_CB(skb)->dccpd_reset_data[2] = len > 1 ? value[1] : 0;
 274        return -1;
 275}
 276
 277EXPORT_SYMBOL_GPL(dccp_parse_options);
 278
 279void dccp_encode_value_var(const u64 value, u8 *to, const u8 len)
 280{
 281        if (len >= DCCP_OPTVAL_MAXLEN)
 282                *to++ = (value & 0xFF0000000000ull) >> 40;
 283        if (len > 4)
 284                *to++ = (value & 0xFF00000000ull) >> 32;
 285        if (len > 3)
 286                *to++ = (value & 0xFF000000) >> 24;
 287        if (len > 2)
 288                *to++ = (value & 0xFF0000) >> 16;
 289        if (len > 1)
 290                *to++ = (value & 0xFF00) >> 8;
 291        if (len > 0)
 292                *to++ = (value & 0xFF);
 293}
 294
 295static inline u8 dccp_ndp_len(const u64 ndp)
 296{
 297        if (likely(ndp <= 0xFF))
 298                return 1;
 299        return likely(ndp <= USHRT_MAX) ? 2 : (ndp <= UINT_MAX ? 4 : 6);
 300}
 301
 302int dccp_insert_option(struct sock *sk, struct sk_buff *skb,
 303                        const unsigned char option,
 304                        const void *value, const unsigned char len)
 305{
 306        unsigned char *to;
 307
 308        if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 2 > DCCP_MAX_OPT_LEN)
 309                return -1;
 310
 311        DCCP_SKB_CB(skb)->dccpd_opt_len += len + 2;
 312
 313        to    = skb_push(skb, len + 2);
 314        *to++ = option;
 315        *to++ = len + 2;
 316
 317        memcpy(to, value, len);
 318        return 0;
 319}
 320
 321EXPORT_SYMBOL_GPL(dccp_insert_option);
 322
 323static int dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb)
 324{
 325        struct dccp_sock *dp = dccp_sk(sk);
 326        u64 ndp = dp->dccps_ndp_count;
 327
 328        if (dccp_non_data_packet(skb))
 329                ++dp->dccps_ndp_count;
 330        else
 331                dp->dccps_ndp_count = 0;
 332
 333        if (ndp > 0) {
 334                unsigned char *ptr;
 335                const int ndp_len = dccp_ndp_len(ndp);
 336                const int len = ndp_len + 2;
 337
 338                if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
 339                        return -1;
 340
 341                DCCP_SKB_CB(skb)->dccpd_opt_len += len;
 342
 343                ptr = skb_push(skb, len);
 344                *ptr++ = DCCPO_NDP_COUNT;
 345                *ptr++ = len;
 346                dccp_encode_value_var(ndp, ptr, ndp_len);
 347        }
 348
 349        return 0;
 350}
 351
 352static inline int dccp_elapsed_time_len(const u32 elapsed_time)
 353{
 354        return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4;
 355}
 356
 357int dccp_insert_option_elapsed_time(struct sock *sk, struct sk_buff *skb,
 358                                    u32 elapsed_time)
 359{
 360        const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time);
 361        const int len = 2 + elapsed_time_len;
 362        unsigned char *to;
 363
 364        if (elapsed_time_len == 0)
 365                return 0;
 366
 367        if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
 368                return -1;
 369
 370        DCCP_SKB_CB(skb)->dccpd_opt_len += len;
 371
 372        to    = skb_push(skb, len);
 373        *to++ = DCCPO_ELAPSED_TIME;
 374        *to++ = len;
 375
 376        if (elapsed_time_len == 2) {
 377                const __be16 var16 = htons((u16)elapsed_time);
 378                memcpy(to, &var16, 2);
 379        } else {
 380                const __be32 var32 = htonl(elapsed_time);
 381                memcpy(to, &var32, 4);
 382        }
 383
 384        return 0;
 385}
 386
 387EXPORT_SYMBOL_GPL(dccp_insert_option_elapsed_time);
 388
 389int dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb)
 390{
 391        __be32 now = htonl(dccp_timestamp());
 392        /* yes this will overflow but that is the point as we want a
 393         * 10 usec 32 bit timer which mean it wraps every 11.9 hours */
 394
 395        return dccp_insert_option(sk, skb, DCCPO_TIMESTAMP, &now, sizeof(now));
 396}
 397
 398EXPORT_SYMBOL_GPL(dccp_insert_option_timestamp);
 399
 400static int dccp_insert_option_timestamp_echo(struct dccp_sock *dp,
 401                                             struct dccp_request_sock *dreq,
 402                                             struct sk_buff *skb)
 403{
 404        __be32 tstamp_echo;
 405        unsigned char *to;
 406        u32 elapsed_time, elapsed_time_len, len;
 407
 408        if (dreq != NULL) {
 409                elapsed_time = dccp_timestamp() - dreq->dreq_timestamp_time;
 410                tstamp_echo  = htonl(dreq->dreq_timestamp_echo);
 411                dreq->dreq_timestamp_echo = 0;
 412        } else {
 413                elapsed_time = dccp_timestamp() - dp->dccps_timestamp_time;
 414                tstamp_echo  = htonl(dp->dccps_timestamp_echo);
 415                dp->dccps_timestamp_echo = 0;
 416        }
 417
 418        elapsed_time_len = dccp_elapsed_time_len(elapsed_time);
 419        len = 6 + elapsed_time_len;
 420
 421        if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
 422                return -1;
 423
 424        DCCP_SKB_CB(skb)->dccpd_opt_len += len;
 425
 426        to    = skb_push(skb, len);
 427        *to++ = DCCPO_TIMESTAMP_ECHO;
 428        *to++ = len;
 429
 430        memcpy(to, &tstamp_echo, 4);
 431        to += 4;
 432
 433        if (elapsed_time_len == 2) {
 434                const __be16 var16 = htons((u16)elapsed_time);
 435                memcpy(to, &var16, 2);
 436        } else if (elapsed_time_len == 4) {
 437                const __be32 var32 = htonl(elapsed_time);
 438                memcpy(to, &var32, 4);
 439        }
 440
 441        return 0;
 442}
 443
 444/**
 445 * dccp_insert_option_mandatory  -  Mandatory option (5.8.2)
 446 * Note that since we are using skb_push, this function needs to be called
 447 * _after_ inserting the option it is supposed to influence (stack order).
 448 */
 449int dccp_insert_option_mandatory(struct sk_buff *skb)
 450{
 451        if (DCCP_SKB_CB(skb)->dccpd_opt_len >= DCCP_MAX_OPT_LEN)
 452                return -1;
 453
 454        DCCP_SKB_CB(skb)->dccpd_opt_len++;
 455        *skb_push(skb, 1) = DCCPO_MANDATORY;
 456        return 0;
 457}
 458
 459/**
 460 * dccp_insert_fn_opt  -  Insert single Feature-Negotiation option into @skb
 461 * @type: %DCCPO_CHANGE_L, %DCCPO_CHANGE_R, %DCCPO_CONFIRM_L, %DCCPO_CONFIRM_R
 462 * @feat: one out of %dccp_feature_numbers
 463 * @val: NN value or SP array (preferred element first) to copy
 464 * @len: true length of @val in bytes (excluding first element repetition)
 465 * @repeat_first: whether to copy the first element of @val twice
 466 * The last argument is used to construct Confirm options, where the preferred
 467 * value and the preference list appear separately (RFC 4340, 6.3.1). Preference
 468 * lists are kept such that the preferred entry is always first, so we only need
 469 * to copy twice, and avoid the overhead of cloning into a bigger array.
 470 */
 471int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
 472                       u8 *val, u8 len, bool repeat_first)
 473{
 474        u8 tot_len, *to;
 475
 476        /* take the `Feature' field and possible repetition into account */
 477        if (len > (DCCP_SINGLE_OPT_MAXLEN - 2)) {
 478                DCCP_WARN("length %u for feature %u too large\n", len, feat);
 479                return -1;
 480        }
 481
 482        if (unlikely(val == NULL || len == 0))
 483                len = repeat_first = 0;
 484        tot_len = 3 + repeat_first + len;
 485
 486        if (DCCP_SKB_CB(skb)->dccpd_opt_len + tot_len > DCCP_MAX_OPT_LEN) {
 487                DCCP_WARN("packet too small for feature %d option!\n", feat);
 488                return -1;
 489        }
 490        DCCP_SKB_CB(skb)->dccpd_opt_len += tot_len;
 491
 492        to    = skb_push(skb, tot_len);
 493        *to++ = type;
 494        *to++ = tot_len;
 495        *to++ = feat;
 496
 497        if (repeat_first)
 498                *to++ = *val;
 499        if (len)
 500                memcpy(to, val, len);
 501        return 0;
 502}
 503
 504/* The length of all options needs to be a multiple of 4 (5.8) */
 505static void dccp_insert_option_padding(struct sk_buff *skb)
 506{
 507        int padding = DCCP_SKB_CB(skb)->dccpd_opt_len % 4;
 508
 509        if (padding != 0) {
 510                padding = 4 - padding;
 511                memset(skb_push(skb, padding), 0, padding);
 512                DCCP_SKB_CB(skb)->dccpd_opt_len += padding;
 513        }
 514}
 515
 516int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 517{
 518        struct dccp_sock *dp = dccp_sk(sk);
 519
 520        DCCP_SKB_CB(skb)->dccpd_opt_len = 0;
 521
 522        if (dp->dccps_send_ndp_count && dccp_insert_option_ndp(sk, skb))
 523                return -1;
 524
 525        if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA) {
 526
 527                /* Feature Negotiation */
 528                if (dccp_feat_insert_opts(dp, NULL, skb))
 529                        return -1;
 530
 531                if (DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_REQUEST) {
 532                        /*
 533                         * Obtain RTT sample from Request/Response exchange.
 534                         * This is currently used in CCID 3 initialisation.
 535                         */
 536                        if (dccp_insert_option_timestamp(sk, skb))
 537                                return -1;
 538
 539                } else if (dp->dccps_hc_rx_ackvec != NULL &&
 540                           dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) &&
 541                           dccp_insert_option_ackvec(sk, skb)) {
 542                                return -1;
 543                }
 544        }
 545
 546        if (dp->dccps_hc_rx_insert_options) {
 547                if (ccid_hc_rx_insert_options(dp->dccps_hc_rx_ccid, sk, skb))
 548                        return -1;
 549                dp->dccps_hc_rx_insert_options = 0;
 550        }
 551
 552        if (dp->dccps_timestamp_echo != 0 &&
 553            dccp_insert_option_timestamp_echo(dp, NULL, skb))
 554                return -1;
 555
 556        dccp_insert_option_padding(skb);
 557        return 0;
 558}
 559
 560int dccp_insert_options_rsk(struct dccp_request_sock *dreq, struct sk_buff *skb)
 561{
 562        DCCP_SKB_CB(skb)->dccpd_opt_len = 0;
 563
 564        if (dccp_feat_insert_opts(NULL, dreq, skb))
 565                return -1;
 566
 567        if (dreq->dreq_timestamp_echo != 0 &&
 568            dccp_insert_option_timestamp_echo(NULL, dreq, skb))
 569                return -1;
 570
 571        dccp_insert_option_padding(skb);
 572        return 0;
 573}
 574
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.