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