@@ -559,6 +559,158 @@ static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq)
559559 x -> repl -> notify (x , XFRM_REPLAY_UPDATE );
560560}
561561
562+ #ifdef CONFIG_XFRM_OFFLOAD
563+ static int xfrm_replay_overflow_offload (struct xfrm_state * x , struct sk_buff * skb )
564+ {
565+ int err = 0 ;
566+ struct net * net = xs_net (x );
567+ struct xfrm_offload * xo = xfrm_offload (skb );
568+ __u32 oseq = x -> replay .oseq ;
569+
570+ if (!xo )
571+ return xfrm_replay_overflow (x , skb );
572+
573+ if (x -> type -> flags & XFRM_TYPE_REPLAY_PROT ) {
574+ if (!skb_is_gso (skb )) {
575+ XFRM_SKB_CB (skb )-> seq .output .low = ++ oseq ;
576+ xo -> seq .low = oseq ;
577+ } else {
578+ XFRM_SKB_CB (skb )-> seq .output .low = oseq + 1 ;
579+ xo -> seq .low = oseq + 1 ;
580+ oseq += skb_shinfo (skb )-> gso_segs ;
581+ }
582+
583+ XFRM_SKB_CB (skb )-> seq .output .hi = 0 ;
584+ xo -> seq .hi = 0 ;
585+ if (unlikely (oseq < x -> replay .oseq )) {
586+ xfrm_audit_state_replay_overflow (x , skb );
587+ err = - EOVERFLOW ;
588+
589+ return err ;
590+ }
591+
592+ x -> replay .oseq = oseq ;
593+
594+ if (xfrm_aevent_is_on (net ))
595+ x -> repl -> notify (x , XFRM_REPLAY_UPDATE );
596+ }
597+
598+ return err ;
599+ }
600+
601+ static int xfrm_replay_overflow_offload_bmp (struct xfrm_state * x , struct sk_buff * skb )
602+ {
603+ int err = 0 ;
604+ struct xfrm_offload * xo = xfrm_offload (skb );
605+ struct xfrm_replay_state_esn * replay_esn = x -> replay_esn ;
606+ struct net * net = xs_net (x );
607+ __u32 oseq = replay_esn -> oseq ;
608+
609+ if (!xo )
610+ return xfrm_replay_overflow_bmp (x , skb );
611+
612+ if (x -> type -> flags & XFRM_TYPE_REPLAY_PROT ) {
613+ if (!skb_is_gso (skb )) {
614+ XFRM_SKB_CB (skb )-> seq .output .low = ++ oseq ;
615+ xo -> seq .low = oseq ;
616+ } else {
617+ XFRM_SKB_CB (skb )-> seq .output .low = oseq + 1 ;
618+ xo -> seq .low = oseq + 1 ;
619+ oseq += skb_shinfo (skb )-> gso_segs ;
620+ }
621+
622+ XFRM_SKB_CB (skb )-> seq .output .hi = 0 ;
623+ xo -> seq .hi = 0 ;
624+ if (unlikely (oseq < replay_esn -> oseq )) {
625+ xfrm_audit_state_replay_overflow (x , skb );
626+ err = - EOVERFLOW ;
627+
628+ return err ;
629+ } else {
630+ replay_esn -> oseq = oseq ;
631+ }
632+
633+ if (xfrm_aevent_is_on (net ))
634+ x -> repl -> notify (x , XFRM_REPLAY_UPDATE );
635+ }
636+
637+ return err ;
638+ }
639+
640+ static int xfrm_replay_overflow_offload_esn (struct xfrm_state * x , struct sk_buff * skb )
641+ {
642+ int err = 0 ;
643+ struct xfrm_offload * xo = xfrm_offload (skb );
644+ struct xfrm_replay_state_esn * replay_esn = x -> replay_esn ;
645+ struct net * net = xs_net (x );
646+ __u32 oseq = replay_esn -> oseq ;
647+ __u32 oseq_hi = replay_esn -> oseq_hi ;
648+
649+ if (!xo )
650+ return xfrm_replay_overflow_esn (x , skb );
651+
652+ if (x -> type -> flags & XFRM_TYPE_REPLAY_PROT ) {
653+ if (!skb_is_gso (skb )) {
654+ XFRM_SKB_CB (skb )-> seq .output .low = ++ oseq ;
655+ XFRM_SKB_CB (skb )-> seq .output .hi = oseq_hi ;
656+ xo -> seq .low = oseq ;
657+ xo -> seq .hi = oseq_hi ;
658+ } else {
659+ XFRM_SKB_CB (skb )-> seq .output .low = oseq + 1 ;
660+ XFRM_SKB_CB (skb )-> seq .output .hi = oseq_hi ;
661+ xo -> seq .low = oseq = oseq + 1 ;
662+ xo -> seq .hi = oseq_hi ;
663+ oseq += skb_shinfo (skb )-> gso_segs ;
664+ }
665+
666+ if (unlikely (oseq < replay_esn -> oseq )) {
667+ XFRM_SKB_CB (skb )-> seq .output .hi = ++ oseq_hi ;
668+ xo -> seq .hi = oseq_hi ;
669+
670+ if (replay_esn -> oseq_hi == 0 ) {
671+ replay_esn -> oseq -- ;
672+ replay_esn -> oseq_hi -- ;
673+ xfrm_audit_state_replay_overflow (x , skb );
674+ err = - EOVERFLOW ;
675+
676+ return err ;
677+ }
678+ }
679+
680+ replay_esn -> oseq = oseq ;
681+ replay_esn -> oseq_hi = oseq_hi ;
682+
683+ if (xfrm_aevent_is_on (net ))
684+ x -> repl -> notify (x , XFRM_REPLAY_UPDATE );
685+ }
686+
687+ return err ;
688+ }
689+
690+ static const struct xfrm_replay xfrm_replay_legacy = {
691+ .advance = xfrm_replay_advance ,
692+ .check = xfrm_replay_check ,
693+ .recheck = xfrm_replay_check ,
694+ .notify = xfrm_replay_notify ,
695+ .overflow = xfrm_replay_overflow_offload ,
696+ };
697+
698+ static const struct xfrm_replay xfrm_replay_bmp = {
699+ .advance = xfrm_replay_advance_bmp ,
700+ .check = xfrm_replay_check_bmp ,
701+ .recheck = xfrm_replay_check_bmp ,
702+ .notify = xfrm_replay_notify_bmp ,
703+ .overflow = xfrm_replay_overflow_offload_bmp ,
704+ };
705+
706+ static const struct xfrm_replay xfrm_replay_esn = {
707+ .advance = xfrm_replay_advance_esn ,
708+ .check = xfrm_replay_check_esn ,
709+ .recheck = xfrm_replay_recheck_esn ,
710+ .notify = xfrm_replay_notify_esn ,
711+ .overflow = xfrm_replay_overflow_offload_esn ,
712+ };
713+ #else
562714static const struct xfrm_replay xfrm_replay_legacy = {
563715 .advance = xfrm_replay_advance ,
564716 .check = xfrm_replay_check ,
@@ -582,6 +734,7 @@ static const struct xfrm_replay xfrm_replay_esn = {
582734 .notify = xfrm_replay_notify_esn ,
583735 .overflow = xfrm_replay_overflow_esn ,
584736};
737+ #endif
585738
586739int xfrm_init_replay (struct xfrm_state * x )
587740{
@@ -596,10 +749,12 @@ int xfrm_init_replay(struct xfrm_state *x)
596749 if (replay_esn -> replay_window == 0 )
597750 return - EINVAL ;
598751 x -> repl = & xfrm_replay_esn ;
599- } else
752+ } else {
600753 x -> repl = & xfrm_replay_bmp ;
601- } else
754+ }
755+ } else {
602756 x -> repl = & xfrm_replay_legacy ;
757+ }
603758
604759 return 0 ;
605760}
0 commit comments