linux/net/xfrm/xfrm_replay.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * xfrm_replay.c - xfrm replay detection, derived from xfrm_state.c.
   4 *
   5 * Copyright (C) 2010 secunet Security Networks AG
   6 * Copyright (C) 2010 Steffen Klassert <steffen.klassert@secunet.com>
   7 */
   8
   9#include <linux/export.h>
  10#include <net/xfrm.h>
  11
  12u32 xfrm_replay_seqhi(struct xfrm_state *x, __be32 net_seq)
  13{
  14        u32 seq, seq_hi, bottom;
  15        struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
  16
  17        if (!(x->props.flags & XFRM_STATE_ESN))
  18                return 0;
  19
  20        seq = ntohl(net_seq);
  21        seq_hi = replay_esn->seq_hi;
  22        bottom = replay_esn->seq - replay_esn->replay_window + 1;
  23
  24        if (likely(replay_esn->seq >= replay_esn->replay_window - 1)) {
  25                /* A. same subspace */
  26                if (unlikely(seq < bottom))
  27                        seq_hi++;
  28        } else {
  29                /* B. window spans two subspaces */
  30                if (unlikely(seq >= bottom))
  31                        seq_hi--;
  32        }
  33
  34        return seq_hi;
  35}
  36EXPORT_SYMBOL(xfrm_replay_seqhi);
  37
  38static void xfrm_replay_notify_bmp(struct xfrm_state *x, int event);
  39static void xfrm_replay_notify_esn(struct xfrm_state *x, int event);
  40
  41void xfrm_replay_notify(struct xfrm_state *x, int event)
  42{
  43        struct km_event c;
  44        /* we send notify messages in case
  45         *  1. we updated on of the sequence numbers, and the seqno difference
  46         *     is at least x->replay_maxdiff, in this case we also update the
  47         *     timeout of our timer function
  48         *  2. if x->replay_maxage has elapsed since last update,
  49         *     and there were changes
  50         *
  51         *  The state structure must be locked!
  52         */
  53
  54        switch (x->repl_mode) {
  55        case XFRM_REPLAY_MODE_LEGACY:
  56                break;
  57        case XFRM_REPLAY_MODE_BMP:
  58                xfrm_replay_notify_bmp(x, event);
  59                return;
  60        case XFRM_REPLAY_MODE_ESN:
  61                xfrm_replay_notify_esn(x, event);
  62                return;
  63        }
  64
  65        switch (event) {
  66        case XFRM_REPLAY_UPDATE:
  67                if (!x->replay_maxdiff ||
  68                    ((x->replay.seq - x->preplay.seq < x->replay_maxdiff) &&
  69                    (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff))) {
  70                        if (x->xflags & XFRM_TIME_DEFER)
  71                                event = XFRM_REPLAY_TIMEOUT;
  72                        else
  73                                return;
  74                }
  75
  76                break;
  77
  78        case XFRM_REPLAY_TIMEOUT:
  79                if (memcmp(&x->replay, &x->preplay,
  80                           sizeof(struct xfrm_replay_state)) == 0) {
  81                        x->xflags |= XFRM_TIME_DEFER;
  82                        return;
  83                }
  84
  85                break;
  86        }
  87
  88        memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state));
  89        c.event = XFRM_MSG_NEWAE;
  90        c.data.aevent = event;
  91        km_state_notify(x, &c);
  92
  93        if (x->replay_maxage &&
  94            !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
  95                x->xflags &= ~XFRM_TIME_DEFER;
  96}
  97
  98static int __xfrm_replay_overflow(struct xfrm_state *x, struct sk_buff *skb)
  99{
 100        int err = 0;
 101        struct net *net = xs_net(x);
 102
 103        if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
 104                XFRM_SKB_CB(skb)->seq.output.low = ++x->replay.oseq;
 105                XFRM_SKB_CB(skb)->seq.output.hi = 0;
 106                if (unlikely(x->replay.oseq == 0) &&
 107                    !(x->props.extra_flags & XFRM_SA_XFLAG_OSEQ_MAY_WRAP)) {
 108                        x->replay.oseq--;
 109                        xfrm_audit_state_replay_overflow(x, skb);
 110                        err = -EOVERFLOW;
 111
 112                        return err;
 113                }
 114                if (xfrm_aevent_is_on(net))
 115                        xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
 116        }
 117
 118        return err;
 119}
 120
 121static int xfrm_replay_check_legacy(struct xfrm_state *x,
 122                                    struct sk_buff *skb, __be32 net_seq)
 123{
 124        u32 diff;
 125        u32 seq = ntohl(net_seq);
 126
 127        if (!x->props.replay_window)
 128                return 0;
 129
 130        if (unlikely(seq == 0))
 131                goto err;
 132
 133        if (likely(seq > x->replay.seq))
 134                return 0;
 135
 136        diff = x->replay.seq - seq;
 137        if (diff >= x->props.replay_window) {
 138                x->stats.replay_window++;
 139                goto err;
 140        }
 141
 142        if (x->replay.bitmap & (1U << diff)) {
 143                x->stats.replay++;
 144                goto err;
 145        }
 146        return 0;
 147
 148err:
 149        xfrm_audit_state_replay(x, skb, net_seq);
 150        return -EINVAL;
 151}
 152
 153static void xfrm_replay_advance_bmp(struct xfrm_state *x, __be32 net_seq);
 154static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq);
 155
 156void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
 157{
 158        u32 diff, seq;
 159
 160        switch (x->repl_mode) {
 161        case XFRM_REPLAY_MODE_LEGACY:
 162                break;
 163        case XFRM_REPLAY_MODE_BMP:
 164                return xfrm_replay_advance_bmp(x, net_seq);
 165        case XFRM_REPLAY_MODE_ESN:
 166                return xfrm_replay_advance_esn(x, net_seq);
 167        }
 168
 169        if (!x->props.replay_window)
 170                return;
 171
 172        seq = ntohl(net_seq);
 173        if (seq > x->replay.seq) {
 174                diff = seq - x->replay.seq;
 175                if (diff < x->props.replay_window)
 176                        x->replay.bitmap = ((x->replay.bitmap) << diff) | 1;
 177                else
 178                        x->replay.bitmap = 1;
 179                x->replay.seq = seq;
 180        } else {
 181                diff = x->replay.seq - seq;
 182                x->replay.bitmap |= (1U << diff);
 183        }
 184
 185        if (xfrm_aevent_is_on(xs_net(x)))
 186                xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
 187}
 188
 189static int xfrm_replay_overflow_bmp(struct xfrm_state *x, struct sk_buff *skb)
 190{
 191        int err = 0;
 192        struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
 193        struct net *net = xs_net(x);
 194
 195        if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
 196                XFRM_SKB_CB(skb)->seq.output.low = ++replay_esn->oseq;
 197                XFRM_SKB_CB(skb)->seq.output.hi = 0;
 198                if (unlikely(replay_esn->oseq == 0) &&
 199                    !(x->props.extra_flags & XFRM_SA_XFLAG_OSEQ_MAY_WRAP)) {
 200                        replay_esn->oseq--;
 201                        xfrm_audit_state_replay_overflow(x, skb);
 202                        err = -EOVERFLOW;
 203
 204                        return err;
 205                }
 206                if (xfrm_aevent_is_on(net))
 207                        xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
 208        }
 209
 210        return err;
 211}
 212
 213static int xfrm_replay_check_bmp(struct xfrm_state *x,
 214                                 struct sk_buff *skb, __be32 net_seq)
 215{
 216        unsigned int bitnr, nr;
 217        struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
 218        u32 pos;
 219        u32 seq = ntohl(net_seq);
 220        u32 diff =  replay_esn->seq - seq;
 221
 222        if (!replay_esn->replay_window)
 223                return 0;
 224
 225        if (unlikely(seq == 0))
 226                goto err;
 227
 228        if (likely(seq > replay_esn->seq))
 229                return 0;
 230
 231        if (diff >= replay_esn->replay_window) {
 232                x->stats.replay_window++;
 233                goto err;
 234        }
 235
 236        pos = (replay_esn->seq - 1) % replay_esn->replay_window;
 237
 238        if (pos >= diff)
 239                bitnr = (pos - diff) % replay_esn->replay_window;
 240        else
 241                bitnr = replay_esn->replay_window - (diff - pos);
 242
 243        nr = bitnr >> 5;
 244        bitnr = bitnr & 0x1F;
 245        if (replay_esn->bmp[nr] & (1U << bitnr))
 246                goto err_replay;
 247
 248        return 0;
 249
 250err_replay:
 251        x->stats.replay++;
 252err:
 253        xfrm_audit_state_replay(x, skb, net_seq);
 254        return -EINVAL;
 255}
 256
 257static void xfrm_replay_advance_bmp(struct xfrm_state *x, __be32 net_seq)
 258{
 259        unsigned int bitnr, nr, i;
 260        u32 diff;
 261        struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
 262        u32 seq = ntohl(net_seq);
 263        u32 pos;
 264
 265        if (!replay_esn->replay_window)
 266                return;
 267
 268        pos = (replay_esn->seq - 1) % replay_esn->replay_window;
 269
 270        if (seq > replay_esn->seq) {
 271                diff = seq - replay_esn->seq;
 272
 273                if (diff < replay_esn->replay_window) {
 274                        for (i = 1; i < diff; i++) {
 275                                bitnr = (pos + i) % replay_esn->replay_window;
 276                                nr = bitnr >> 5;
 277                                bitnr = bitnr & 0x1F;
 278                                replay_esn->bmp[nr] &=  ~(1U << bitnr);
 279                        }
 280                } else {
 281                        nr = (replay_esn->replay_window - 1) >> 5;
 282                        for (i = 0; i <= nr; i++)
 283                                replay_esn->bmp[i] = 0;
 284                }
 285
 286                bitnr = (pos + diff) % replay_esn->replay_window;
 287                replay_esn->seq = seq;
 288        } else {
 289                diff = replay_esn->seq - seq;
 290
 291                if (pos >= diff)
 292                        bitnr = (pos - diff) % replay_esn->replay_window;
 293                else
 294                        bitnr = replay_esn->replay_window - (diff - pos);
 295        }
 296
 297        nr = bitnr >> 5;
 298        bitnr = bitnr & 0x1F;
 299        replay_esn->bmp[nr] |= (1U << bitnr);
 300
 301        if (xfrm_aevent_is_on(xs_net(x)))
 302                xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
 303}
 304
 305static void xfrm_replay_notify_bmp(struct xfrm_state *x, int event)
 306{
 307        struct km_event c;
 308        struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
 309        struct xfrm_replay_state_esn *preplay_esn = x->preplay_esn;
 310
 311        /* we send notify messages in case
 312         *  1. we updated on of the sequence numbers, and the seqno difference
 313         *     is at least x->replay_maxdiff, in this case we also update the
 314         *     timeout of our timer function
 315         *  2. if x->replay_maxage has elapsed since last update,
 316         *     and there were changes
 317         *
 318         *  The state structure must be locked!
 319         */
 320
 321        switch (event) {
 322        case XFRM_REPLAY_UPDATE:
 323                if (!x->replay_maxdiff ||
 324                    ((replay_esn->seq - preplay_esn->seq < x->replay_maxdiff) &&
 325                    (replay_esn->oseq - preplay_esn->oseq
 326                     < x->replay_maxdiff))) {
 327                        if (x->xflags & XFRM_TIME_DEFER)
 328                                event = XFRM_REPLAY_TIMEOUT;
 329                        else
 330                                return;
 331                }
 332
 333                break;
 334
 335        case XFRM_REPLAY_TIMEOUT:
 336                if (memcmp(x->replay_esn, x->preplay_esn,
 337                           xfrm_replay_state_esn_len(replay_esn)) == 0) {
 338                        x->xflags |= XFRM_TIME_DEFER;
 339                        return;
 340                }
 341
 342                break;
 343        }
 344
 345        memcpy(x->preplay_esn, x->replay_esn,
 346               xfrm_replay_state_esn_len(replay_esn));
 347        c.event = XFRM_MSG_NEWAE;
 348        c.data.aevent = event;
 349        km_state_notify(x, &c);
 350
 351        if (x->replay_maxage &&
 352            !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
 353                x->xflags &= ~XFRM_TIME_DEFER;
 354}
 355
 356static void xfrm_replay_notify_esn(struct xfrm_state *x, int event)
 357{
 358        u32 seq_diff, oseq_diff;
 359        struct km_event c;
 360        struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
 361        struct xfrm_replay_state_esn *preplay_esn = x->preplay_esn;
 362
 363        /* we send notify messages in case
 364         *  1. we updated on of the sequence numbers, and the seqno difference
 365         *     is at least x->replay_maxdiff, in this case we also update the
 366         *     timeout of our timer function
 367         *  2. if x->replay_maxage has elapsed since last update,
 368         *     and there were changes
 369         *
 370         *  The state structure must be locked!
 371         */
 372
 373        switch (event) {
 374        case XFRM_REPLAY_UPDATE:
 375                if (x->replay_maxdiff) {
 376                        if (replay_esn->seq_hi == preplay_esn->seq_hi)
 377                                seq_diff = replay_esn->seq - preplay_esn->seq;
 378                        else
 379                                seq_diff = ~preplay_esn->seq + replay_esn->seq
 380                                           + 1;
 381
 382                        if (replay_esn->oseq_hi == preplay_esn->oseq_hi)
 383                                oseq_diff = replay_esn->oseq
 384                                            - preplay_esn->oseq;
 385                        else
 386                                oseq_diff = ~preplay_esn->oseq
 387                                            + replay_esn->oseq + 1;
 388
 389                        if (seq_diff >= x->replay_maxdiff ||
 390                            oseq_diff >= x->replay_maxdiff)
 391                                break;
 392                }
 393
 394                if (x->xflags & XFRM_TIME_DEFER)
 395                        event = XFRM_REPLAY_TIMEOUT;
 396                else
 397                        return;
 398
 399                break;
 400
 401        case XFRM_REPLAY_TIMEOUT:
 402                if (memcmp(x->replay_esn, x->preplay_esn,
 403                           xfrm_replay_state_esn_len(replay_esn)) == 0) {
 404                        x->xflags |= XFRM_TIME_DEFER;
 405                        return;
 406                }
 407
 408                break;
 409        }
 410
 411        memcpy(x->preplay_esn, x->replay_esn,
 412               xfrm_replay_state_esn_len(replay_esn));
 413        c.event = XFRM_MSG_NEWAE;
 414        c.data.aevent = event;
 415        km_state_notify(x, &c);
 416
 417        if (x->replay_maxage &&
 418            !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
 419                x->xflags &= ~XFRM_TIME_DEFER;
 420}
 421
 422static int xfrm_replay_overflow_esn(struct xfrm_state *x, struct sk_buff *skb)
 423{
 424        int err = 0;
 425        struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
 426        struct net *net = xs_net(x);
 427
 428        if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
 429                XFRM_SKB_CB(skb)->seq.output.low = ++replay_esn->oseq;
 430                XFRM_SKB_CB(skb)->seq.output.hi = replay_esn->oseq_hi;
 431
 432                if (unlikely(replay_esn->oseq == 0)) {
 433                        XFRM_SKB_CB(skb)->seq.output.hi = ++replay_esn->oseq_hi;
 434
 435                        if (replay_esn->oseq_hi == 0) {
 436                                replay_esn->oseq--;
 437                                replay_esn->oseq_hi--;
 438                                xfrm_audit_state_replay_overflow(x, skb);
 439                                err = -EOVERFLOW;
 440
 441                                return err;
 442                        }
 443                }
 444                if (xfrm_aevent_is_on(net))
 445                        xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
 446        }
 447
 448        return err;
 449}
 450
 451static int xfrm_replay_check_esn(struct xfrm_state *x,
 452                                 struct sk_buff *skb, __be32 net_seq)
 453{
 454        unsigned int bitnr, nr;
 455        u32 diff;
 456        struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
 457        u32 pos;
 458        u32 seq = ntohl(net_seq);
 459        u32 wsize = replay_esn->replay_window;
 460        u32 top = replay_esn->seq;
 461        u32 bottom = top - wsize + 1;
 462
 463        if (!wsize)
 464                return 0;
 465
 466        if (unlikely(seq == 0 && replay_esn->seq_hi == 0 &&
 467                     (replay_esn->seq < replay_esn->replay_window - 1)))
 468                goto err;
 469
 470        diff = top - seq;
 471
 472        if (likely(top >= wsize - 1)) {
 473                /* A. same subspace */
 474                if (likely(seq > top) || seq < bottom)
 475                        return 0;
 476        } else {
 477                /* B. window spans two subspaces */
 478                if (likely(seq > top && seq < bottom))
 479                        return 0;
 480                if (seq >= bottom)
 481                        diff = ~seq + top + 1;
 482        }
 483
 484        if (diff >= replay_esn->replay_window) {
 485                x->stats.replay_window++;
 486                goto err;
 487        }
 488
 489        pos = (replay_esn->seq - 1) % replay_esn->replay_window;
 490
 491        if (pos >= diff)
 492                bitnr = (pos - diff) % replay_esn->replay_window;
 493        else
 494                bitnr = replay_esn->replay_window - (diff - pos);
 495
 496        nr = bitnr >> 5;
 497        bitnr = bitnr & 0x1F;
 498        if (replay_esn->bmp[nr] & (1U << bitnr))
 499                goto err_replay;
 500
 501        return 0;
 502
 503err_replay:
 504        x->stats.replay++;
 505err:
 506        xfrm_audit_state_replay(x, skb, net_seq);
 507        return -EINVAL;
 508}
 509
 510int xfrm_replay_check(struct xfrm_state *x,
 511                      struct sk_buff *skb, __be32 net_seq)
 512{
 513        switch (x->repl_mode) {
 514        case XFRM_REPLAY_MODE_LEGACY:
 515                break;
 516        case XFRM_REPLAY_MODE_BMP:
 517                return xfrm_replay_check_bmp(x, skb, net_seq);
 518        case XFRM_REPLAY_MODE_ESN:
 519                return xfrm_replay_check_esn(x, skb, net_seq);
 520        }
 521
 522        return xfrm_replay_check_legacy(x, skb, net_seq);
 523}
 524
 525static int xfrm_replay_recheck_esn(struct xfrm_state *x,
 526                                   struct sk_buff *skb, __be32 net_seq)
 527{
 528        if (unlikely(XFRM_SKB_CB(skb)->seq.input.hi !=
 529                     htonl(xfrm_replay_seqhi(x, net_seq)))) {
 530                        x->stats.replay_window++;
 531                        return -EINVAL;
 532        }
 533
 534        return xfrm_replay_check_esn(x, skb, net_seq);
 535}
 536
 537int xfrm_replay_recheck(struct xfrm_state *x,
 538                        struct sk_buff *skb, __be32 net_seq)
 539{
 540        switch (x->repl_mode) {
 541        case XFRM_REPLAY_MODE_LEGACY:
 542                break;
 543        case XFRM_REPLAY_MODE_BMP:
 544                /* no special recheck treatment */
 545                return xfrm_replay_check_bmp(x, skb, net_seq);
 546        case XFRM_REPLAY_MODE_ESN:
 547                return xfrm_replay_recheck_esn(x, skb, net_seq);
 548        }
 549
 550        return xfrm_replay_check_legacy(x, skb, net_seq);
 551}
 552
 553static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq)
 554{
 555        unsigned int bitnr, nr, i;
 556        int wrap;
 557        u32 diff, pos, seq, seq_hi;
 558        struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
 559
 560        if (!replay_esn->replay_window)
 561                return;
 562
 563        seq = ntohl(net_seq);
 564        pos = (replay_esn->seq - 1) % replay_esn->replay_window;
 565        seq_hi = xfrm_replay_seqhi(x, net_seq);
 566        wrap = seq_hi - replay_esn->seq_hi;
 567
 568        if ((!wrap && seq > replay_esn->seq) || wrap > 0) {
 569                if (likely(!wrap))
 570                        diff = seq - replay_esn->seq;
 571                else
 572                        diff = ~replay_esn->seq + seq + 1;
 573
 574                if (diff < replay_esn->replay_window) {
 575                        for (i = 1; i < diff; i++) {
 576                                bitnr = (pos + i) % replay_esn->replay_window;
 577                                nr = bitnr >> 5;
 578                                bitnr = bitnr & 0x1F;
 579                                replay_esn->bmp[nr] &=  ~(1U << bitnr);
 580                        }
 581                } else {
 582                        nr = (replay_esn->replay_window - 1) >> 5;
 583                        for (i = 0; i <= nr; i++)
 584                                replay_esn->bmp[i] = 0;
 585                }
 586
 587                bitnr = (pos + diff) % replay_esn->replay_window;
 588                replay_esn->seq = seq;
 589
 590                if (unlikely(wrap > 0))
 591                        replay_esn->seq_hi++;
 592        } else {
 593                diff = replay_esn->seq - seq;
 594
 595                if (pos >= diff)
 596                        bitnr = (pos - diff) % replay_esn->replay_window;
 597                else
 598                        bitnr = replay_esn->replay_window - (diff - pos);
 599        }
 600
 601        xfrm_dev_state_advance_esn(x);
 602
 603        nr = bitnr >> 5;
 604        bitnr = bitnr & 0x1F;
 605        replay_esn->bmp[nr] |= (1U << bitnr);
 606
 607        if (xfrm_aevent_is_on(xs_net(x)))
 608                xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
 609}
 610
 611#ifdef CONFIG_XFRM_OFFLOAD
 612static int xfrm_replay_overflow_offload(struct xfrm_state *x, struct sk_buff *skb)
 613{
 614        int err = 0;
 615        struct net *net = xs_net(x);
 616        struct xfrm_offload *xo = xfrm_offload(skb);
 617        __u32 oseq = x->replay.oseq;
 618
 619        if (!xo)
 620                return __xfrm_replay_overflow(x, skb);
 621
 622        if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
 623                if (!skb_is_gso(skb)) {
 624                        XFRM_SKB_CB(skb)->seq.output.low = ++oseq;
 625                        xo->seq.low = oseq;
 626                } else {
 627                        XFRM_SKB_CB(skb)->seq.output.low = oseq + 1;
 628                        xo->seq.low = oseq + 1;
 629                        oseq += skb_shinfo(skb)->gso_segs;
 630                }
 631
 632                XFRM_SKB_CB(skb)->seq.output.hi = 0;
 633                xo->seq.hi = 0;
 634                if (unlikely(oseq < x->replay.oseq) &&
 635                    !(x->props.extra_flags & XFRM_SA_XFLAG_OSEQ_MAY_WRAP)) {
 636                        xfrm_audit_state_replay_overflow(x, skb);
 637                        err = -EOVERFLOW;
 638
 639                        return err;
 640                }
 641
 642                x->replay.oseq = oseq;
 643
 644                if (xfrm_aevent_is_on(net))
 645                        xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
 646        }
 647
 648        return err;
 649}
 650
 651static int xfrm_replay_overflow_offload_bmp(struct xfrm_state *x, struct sk_buff *skb)
 652{
 653        int err = 0;
 654        struct xfrm_offload *xo = xfrm_offload(skb);
 655        struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
 656        struct net *net = xs_net(x);
 657        __u32 oseq = replay_esn->oseq;
 658
 659        if (!xo)
 660                return xfrm_replay_overflow_bmp(x, skb);
 661
 662        if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
 663                if (!skb_is_gso(skb)) {
 664                        XFRM_SKB_CB(skb)->seq.output.low = ++oseq;
 665                        xo->seq.low = oseq;
 666                } else {
 667                        XFRM_SKB_CB(skb)->seq.output.low = oseq + 1;
 668                        xo->seq.low = oseq + 1;
 669                        oseq += skb_shinfo(skb)->gso_segs;
 670                }
 671
 672                XFRM_SKB_CB(skb)->seq.output.hi = 0;
 673                xo->seq.hi = 0;
 674                if (unlikely(oseq < replay_esn->oseq) &&
 675                    !(x->props.extra_flags & XFRM_SA_XFLAG_OSEQ_MAY_WRAP)) {
 676                        xfrm_audit_state_replay_overflow(x, skb);
 677                        err = -EOVERFLOW;
 678
 679                        return err;
 680                } else {
 681                        replay_esn->oseq = oseq;
 682                }
 683
 684                if (xfrm_aevent_is_on(net))
 685                        xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
 686        }
 687
 688        return err;
 689}
 690
 691static int xfrm_replay_overflow_offload_esn(struct xfrm_state *x, struct sk_buff *skb)
 692{
 693        int err = 0;
 694        struct xfrm_offload *xo = xfrm_offload(skb);
 695        struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
 696        struct net *net = xs_net(x);
 697        __u32 oseq = replay_esn->oseq;
 698        __u32 oseq_hi = replay_esn->oseq_hi;
 699
 700        if (!xo)
 701                return xfrm_replay_overflow_esn(x, skb);
 702
 703        if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
 704                if (!skb_is_gso(skb)) {
 705                        XFRM_SKB_CB(skb)->seq.output.low = ++oseq;
 706                        XFRM_SKB_CB(skb)->seq.output.hi = oseq_hi;
 707                        xo->seq.low = oseq;
 708                        xo->seq.hi = oseq_hi;
 709                } else {
 710                        XFRM_SKB_CB(skb)->seq.output.low = oseq + 1;
 711                        XFRM_SKB_CB(skb)->seq.output.hi = oseq_hi;
 712                        xo->seq.low = oseq + 1;
 713                        xo->seq.hi = oseq_hi;
 714                        oseq += skb_shinfo(skb)->gso_segs;
 715                }
 716
 717                if (unlikely(oseq < replay_esn->oseq)) {
 718                        XFRM_SKB_CB(skb)->seq.output.hi = ++oseq_hi;
 719                        xo->seq.hi = oseq_hi;
 720                        replay_esn->oseq_hi = oseq_hi;
 721                        if (replay_esn->oseq_hi == 0) {
 722                                replay_esn->oseq--;
 723                                replay_esn->oseq_hi--;
 724                                xfrm_audit_state_replay_overflow(x, skb);
 725                                err = -EOVERFLOW;
 726
 727                                return err;
 728                        }
 729                }
 730
 731                replay_esn->oseq = oseq;
 732
 733                if (xfrm_aevent_is_on(net))
 734                        xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
 735        }
 736
 737        return err;
 738}
 739
 740int xfrm_replay_overflow(struct xfrm_state *x, struct sk_buff *skb)
 741{
 742        switch (x->repl_mode) {
 743        case XFRM_REPLAY_MODE_LEGACY:
 744                break;
 745        case XFRM_REPLAY_MODE_BMP:
 746                return xfrm_replay_overflow_offload_bmp(x, skb);
 747        case XFRM_REPLAY_MODE_ESN:
 748                return xfrm_replay_overflow_offload_esn(x, skb);
 749        }
 750
 751        return xfrm_replay_overflow_offload(x, skb);
 752}
 753#else
 754int xfrm_replay_overflow(struct xfrm_state *x, struct sk_buff *skb)
 755{
 756        switch (x->repl_mode) {
 757        case XFRM_REPLAY_MODE_LEGACY:
 758                break;
 759        case XFRM_REPLAY_MODE_BMP:
 760                return xfrm_replay_overflow_bmp(x, skb);
 761        case XFRM_REPLAY_MODE_ESN:
 762                return xfrm_replay_overflow_esn(x, skb);
 763        }
 764
 765        return __xfrm_replay_overflow(x, skb);
 766}
 767#endif
 768
 769int xfrm_init_replay(struct xfrm_state *x)
 770{
 771        struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
 772
 773        if (replay_esn) {
 774                if (replay_esn->replay_window >
 775                    replay_esn->bmp_len * sizeof(__u32) * 8)
 776                        return -EINVAL;
 777
 778                if (x->props.flags & XFRM_STATE_ESN) {
 779                        if (replay_esn->replay_window == 0)
 780                                return -EINVAL;
 781                        x->repl_mode = XFRM_REPLAY_MODE_ESN;
 782                } else {
 783                        x->repl_mode = XFRM_REPLAY_MODE_BMP;
 784                }
 785        } else {
 786                x->repl_mode = XFRM_REPLAY_MODE_LEGACY;
 787        }
 788
 789        return 0;
 790}
 791EXPORT_SYMBOL(xfrm_init_replay);
 792