2 * xfrm_replay.c - xfrm replay detection, derived from xfrm_state.c.
4 * Copyright (C) 2010 secunet Security Networks AG
5 * Copyright (C) 2010 Steffen Klassert <steffen.klassert@secunet.com>
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms and conditions of the GNU General Public License,
9 * version 2, as published by the Free Software Foundation.
11 * This program is distributed in the hope it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21 #include <linux/export.h>
24 u32
xfrm_replay_seqhi(struct xfrm_state
*x
, __be32 net_seq
)
26 u32 seq
, seq_hi
, bottom
;
27 struct xfrm_replay_state_esn
*replay_esn
= x
->replay_esn
;
29 if (!(x
->props
.flags
& XFRM_STATE_ESN
))
33 seq_hi
= replay_esn
->seq_hi
;
34 bottom
= replay_esn
->seq
- replay_esn
->replay_window
+ 1;
36 if (likely(replay_esn
->seq
>= replay_esn
->replay_window
- 1)) {
37 /* A. same subspace */
38 if (unlikely(seq
< bottom
))
41 /* B. window spans two subspaces */
42 if (unlikely(seq
>= bottom
))
49 static void xfrm_replay_notify(struct xfrm_state
*x
, int event
)
52 /* we send notify messages in case
53 * 1. we updated on of the sequence numbers, and the seqno difference
54 * is at least x->replay_maxdiff, in this case we also update the
55 * timeout of our timer function
56 * 2. if x->replay_maxage has elapsed since last update,
57 * and there were changes
59 * The state structure must be locked!
63 case XFRM_REPLAY_UPDATE
:
64 if (x
->replay_maxdiff
&&
65 (x
->replay
.seq
- x
->preplay
.seq
< x
->replay_maxdiff
) &&
66 (x
->replay
.oseq
- x
->preplay
.oseq
< x
->replay_maxdiff
)) {
67 if (x
->xflags
& XFRM_TIME_DEFER
)
68 event
= XFRM_REPLAY_TIMEOUT
;
75 case XFRM_REPLAY_TIMEOUT
:
76 if (memcmp(&x
->replay
, &x
->preplay
,
77 sizeof(struct xfrm_replay_state
)) == 0) {
78 x
->xflags
|= XFRM_TIME_DEFER
;
85 memcpy(&x
->preplay
, &x
->replay
, sizeof(struct xfrm_replay_state
));
86 c
.event
= XFRM_MSG_NEWAE
;
87 c
.data
.aevent
= event
;
88 km_state_notify(x
, &c
);
90 if (x
->replay_maxage
&&
91 !mod_timer(&x
->rtimer
, jiffies
+ x
->replay_maxage
))
92 x
->xflags
&= ~XFRM_TIME_DEFER
;
95 static int xfrm_replay_overflow(struct xfrm_state
*x
, struct sk_buff
*skb
)
98 struct net
*net
= xs_net(x
);
100 if (x
->type
->flags
& XFRM_TYPE_REPLAY_PROT
) {
101 XFRM_SKB_CB(skb
)->seq
.output
.low
= ++x
->replay
.oseq
;
102 if (unlikely(x
->replay
.oseq
== 0)) {
104 xfrm_audit_state_replay_overflow(x
, skb
);
109 if (xfrm_aevent_is_on(net
))
110 x
->repl
->notify(x
, XFRM_REPLAY_UPDATE
);
116 static int xfrm_replay_check(struct xfrm_state
*x
,
117 struct sk_buff
*skb
, __be32 net_seq
)
120 u32 seq
= ntohl(net_seq
);
122 if (!x
->props
.replay_window
)
125 if (unlikely(seq
== 0))
128 if (likely(seq
> x
->replay
.seq
))
131 diff
= x
->replay
.seq
- seq
;
132 if (diff
>= min_t(unsigned int, x
->props
.replay_window
,
133 sizeof(x
->replay
.bitmap
) * 8)) {
134 x
->stats
.replay_window
++;
138 if (x
->replay
.bitmap
& (1U << diff
)) {
145 xfrm_audit_state_replay(x
, skb
, net_seq
);
149 static void xfrm_replay_advance(struct xfrm_state
*x
, __be32 net_seq
)
152 u32 seq
= ntohl(net_seq
);
154 if (!x
->props
.replay_window
)
157 if (seq
> x
->replay
.seq
) {
158 diff
= seq
- x
->replay
.seq
;
159 if (diff
< x
->props
.replay_window
)
160 x
->replay
.bitmap
= ((x
->replay
.bitmap
) << diff
) | 1;
162 x
->replay
.bitmap
= 1;
165 diff
= x
->replay
.seq
- seq
;
166 x
->replay
.bitmap
|= (1U << diff
);
169 if (xfrm_aevent_is_on(xs_net(x
)))
170 x
->repl
->notify(x
, XFRM_REPLAY_UPDATE
);
173 static int xfrm_replay_overflow_bmp(struct xfrm_state
*x
, struct sk_buff
*skb
)
176 struct xfrm_replay_state_esn
*replay_esn
= x
->replay_esn
;
177 struct net
*net
= xs_net(x
);
179 if (x
->type
->flags
& XFRM_TYPE_REPLAY_PROT
) {
180 XFRM_SKB_CB(skb
)->seq
.output
.low
= ++replay_esn
->oseq
;
181 if (unlikely(replay_esn
->oseq
== 0)) {
183 xfrm_audit_state_replay_overflow(x
, skb
);
188 if (xfrm_aevent_is_on(net
))
189 x
->repl
->notify(x
, XFRM_REPLAY_UPDATE
);
195 static int xfrm_replay_check_bmp(struct xfrm_state
*x
,
196 struct sk_buff
*skb
, __be32 net_seq
)
198 unsigned int bitnr
, nr
;
199 struct xfrm_replay_state_esn
*replay_esn
= x
->replay_esn
;
201 u32 seq
= ntohl(net_seq
);
202 u32 diff
= replay_esn
->seq
- seq
;
204 if (!replay_esn
->replay_window
)
207 if (unlikely(seq
== 0))
210 if (likely(seq
> replay_esn
->seq
))
213 if (diff
>= replay_esn
->replay_window
) {
214 x
->stats
.replay_window
++;
218 pos
= (replay_esn
->seq
- 1) % replay_esn
->replay_window
;
221 bitnr
= (pos
- diff
) % replay_esn
->replay_window
;
223 bitnr
= replay_esn
->replay_window
- (diff
- pos
);
226 bitnr
= bitnr
& 0x1F;
227 if (replay_esn
->bmp
[nr
] & (1U << bitnr
))
235 xfrm_audit_state_replay(x
, skb
, net_seq
);
239 static void xfrm_replay_advance_bmp(struct xfrm_state
*x
, __be32 net_seq
)
241 unsigned int bitnr
, nr
, i
;
243 struct xfrm_replay_state_esn
*replay_esn
= x
->replay_esn
;
244 u32 seq
= ntohl(net_seq
);
247 if (!replay_esn
->replay_window
)
250 pos
= (replay_esn
->seq
- 1) % replay_esn
->replay_window
;
252 if (seq
> replay_esn
->seq
) {
253 diff
= seq
- replay_esn
->seq
;
255 if (diff
< replay_esn
->replay_window
) {
256 for (i
= 1; i
< diff
; i
++) {
257 bitnr
= (pos
+ i
) % replay_esn
->replay_window
;
259 bitnr
= bitnr
& 0x1F;
260 replay_esn
->bmp
[nr
] &= ~(1U << bitnr
);
263 nr
= (replay_esn
->replay_window
- 1) >> 5;
264 for (i
= 0; i
<= nr
; i
++)
265 replay_esn
->bmp
[i
] = 0;
268 bitnr
= (pos
+ diff
) % replay_esn
->replay_window
;
269 replay_esn
->seq
= seq
;
271 diff
= replay_esn
->seq
- seq
;
274 bitnr
= (pos
- diff
) % replay_esn
->replay_window
;
276 bitnr
= replay_esn
->replay_window
- (diff
- pos
);
280 bitnr
= bitnr
& 0x1F;
281 replay_esn
->bmp
[nr
] |= (1U << bitnr
);
283 if (xfrm_aevent_is_on(xs_net(x
)))
284 x
->repl
->notify(x
, XFRM_REPLAY_UPDATE
);
287 static void xfrm_replay_notify_bmp(struct xfrm_state
*x
, int event
)
290 struct xfrm_replay_state_esn
*replay_esn
= x
->replay_esn
;
291 struct xfrm_replay_state_esn
*preplay_esn
= x
->preplay_esn
;
293 /* we send notify messages in case
294 * 1. we updated on of the sequence numbers, and the seqno difference
295 * is at least x->replay_maxdiff, in this case we also update the
296 * timeout of our timer function
297 * 2. if x->replay_maxage has elapsed since last update,
298 * and there were changes
300 * The state structure must be locked!
304 case XFRM_REPLAY_UPDATE
:
305 if (x
->replay_maxdiff
&&
306 (replay_esn
->seq
- preplay_esn
->seq
< x
->replay_maxdiff
) &&
307 (replay_esn
->oseq
- preplay_esn
->oseq
< x
->replay_maxdiff
)) {
308 if (x
->xflags
& XFRM_TIME_DEFER
)
309 event
= XFRM_REPLAY_TIMEOUT
;
316 case XFRM_REPLAY_TIMEOUT
:
317 if (memcmp(x
->replay_esn
, x
->preplay_esn
,
318 xfrm_replay_state_esn_len(replay_esn
)) == 0) {
319 x
->xflags
|= XFRM_TIME_DEFER
;
326 memcpy(x
->preplay_esn
, x
->replay_esn
,
327 xfrm_replay_state_esn_len(replay_esn
));
328 c
.event
= XFRM_MSG_NEWAE
;
329 c
.data
.aevent
= event
;
330 km_state_notify(x
, &c
);
332 if (x
->replay_maxage
&&
333 !mod_timer(&x
->rtimer
, jiffies
+ x
->replay_maxage
))
334 x
->xflags
&= ~XFRM_TIME_DEFER
;
337 static void xfrm_replay_notify_esn(struct xfrm_state
*x
, int event
)
339 u32 seq_diff
, oseq_diff
;
341 struct xfrm_replay_state_esn
*replay_esn
= x
->replay_esn
;
342 struct xfrm_replay_state_esn
*preplay_esn
= x
->preplay_esn
;
344 /* we send notify messages in case
345 * 1. we updated on of the sequence numbers, and the seqno difference
346 * is at least x->replay_maxdiff, in this case we also update the
347 * timeout of our timer function
348 * 2. if x->replay_maxage has elapsed since last update,
349 * and there were changes
351 * The state structure must be locked!
355 case XFRM_REPLAY_UPDATE
:
356 if (!x
->replay_maxdiff
)
359 if (replay_esn
->seq_hi
== preplay_esn
->seq_hi
)
360 seq_diff
= replay_esn
->seq
- preplay_esn
->seq
;
362 seq_diff
= ~preplay_esn
->seq
+ replay_esn
->seq
+ 1;
364 if (replay_esn
->oseq_hi
== preplay_esn
->oseq_hi
)
365 oseq_diff
= replay_esn
->oseq
- preplay_esn
->oseq
;
367 oseq_diff
= ~preplay_esn
->oseq
+ replay_esn
->oseq
+ 1;
369 if (seq_diff
< x
->replay_maxdiff
&&
370 oseq_diff
< x
->replay_maxdiff
) {
372 if (x
->xflags
& XFRM_TIME_DEFER
)
373 event
= XFRM_REPLAY_TIMEOUT
;
380 case XFRM_REPLAY_TIMEOUT
:
381 if (memcmp(x
->replay_esn
, x
->preplay_esn
,
382 xfrm_replay_state_esn_len(replay_esn
)) == 0) {
383 x
->xflags
|= XFRM_TIME_DEFER
;
390 memcpy(x
->preplay_esn
, x
->replay_esn
,
391 xfrm_replay_state_esn_len(replay_esn
));
392 c
.event
= XFRM_MSG_NEWAE
;
393 c
.data
.aevent
= event
;
394 km_state_notify(x
, &c
);
396 if (x
->replay_maxage
&&
397 !mod_timer(&x
->rtimer
, jiffies
+ x
->replay_maxage
))
398 x
->xflags
&= ~XFRM_TIME_DEFER
;
401 static int xfrm_replay_overflow_esn(struct xfrm_state
*x
, struct sk_buff
*skb
)
404 struct xfrm_replay_state_esn
*replay_esn
= x
->replay_esn
;
405 struct net
*net
= xs_net(x
);
407 if (x
->type
->flags
& XFRM_TYPE_REPLAY_PROT
) {
408 XFRM_SKB_CB(skb
)->seq
.output
.low
= ++replay_esn
->oseq
;
409 XFRM_SKB_CB(skb
)->seq
.output
.hi
= replay_esn
->oseq_hi
;
411 if (unlikely(replay_esn
->oseq
== 0)) {
412 XFRM_SKB_CB(skb
)->seq
.output
.hi
= ++replay_esn
->oseq_hi
;
414 if (replay_esn
->oseq_hi
== 0) {
416 replay_esn
->oseq_hi
--;
417 xfrm_audit_state_replay_overflow(x
, skb
);
423 if (xfrm_aevent_is_on(net
))
424 x
->repl
->notify(x
, XFRM_REPLAY_UPDATE
);
430 static int xfrm_replay_check_esn(struct xfrm_state
*x
,
431 struct sk_buff
*skb
, __be32 net_seq
)
433 unsigned int bitnr
, nr
;
435 struct xfrm_replay_state_esn
*replay_esn
= x
->replay_esn
;
437 u32 seq
= ntohl(net_seq
);
438 u32 wsize
= replay_esn
->replay_window
;
439 u32 top
= replay_esn
->seq
;
440 u32 bottom
= top
- wsize
+ 1;
445 if (unlikely(seq
== 0 && replay_esn
->seq_hi
== 0 &&
446 (replay_esn
->seq
< replay_esn
->replay_window
- 1)))
451 if (likely(top
>= wsize
- 1)) {
452 /* A. same subspace */
453 if (likely(seq
> top
) || seq
< bottom
)
456 /* B. window spans two subspaces */
457 if (likely(seq
> top
&& seq
< bottom
))
460 diff
= ~seq
+ top
+ 1;
463 if (diff
>= replay_esn
->replay_window
) {
464 x
->stats
.replay_window
++;
468 pos
= (replay_esn
->seq
- 1) % replay_esn
->replay_window
;
471 bitnr
= (pos
- diff
) % replay_esn
->replay_window
;
473 bitnr
= replay_esn
->replay_window
- (diff
- pos
);
476 bitnr
= bitnr
& 0x1F;
477 if (replay_esn
->bmp
[nr
] & (1U << bitnr
))
485 xfrm_audit_state_replay(x
, skb
, net_seq
);
489 static int xfrm_replay_recheck_esn(struct xfrm_state
*x
,
490 struct sk_buff
*skb
, __be32 net_seq
)
492 if (unlikely(XFRM_SKB_CB(skb
)->seq
.input
.hi
!=
493 htonl(xfrm_replay_seqhi(x
, net_seq
)))) {
494 x
->stats
.replay_window
++;
498 return xfrm_replay_check_esn(x
, skb
, net_seq
);
501 static void xfrm_replay_advance_esn(struct xfrm_state
*x
, __be32 net_seq
)
503 unsigned int bitnr
, nr
, i
;
505 u32 diff
, pos
, seq
, seq_hi
;
506 struct xfrm_replay_state_esn
*replay_esn
= x
->replay_esn
;
508 if (!replay_esn
->replay_window
)
511 seq
= ntohl(net_seq
);
512 pos
= (replay_esn
->seq
- 1) % replay_esn
->replay_window
;
513 seq_hi
= xfrm_replay_seqhi(x
, net_seq
);
514 wrap
= seq_hi
- replay_esn
->seq_hi
;
516 if ((!wrap
&& seq
> replay_esn
->seq
) || wrap
> 0) {
518 diff
= seq
- replay_esn
->seq
;
520 diff
= ~replay_esn
->seq
+ seq
+ 1;
522 if (diff
< replay_esn
->replay_window
) {
523 for (i
= 1; i
< diff
; i
++) {
524 bitnr
= (pos
+ i
) % replay_esn
->replay_window
;
526 bitnr
= bitnr
& 0x1F;
527 replay_esn
->bmp
[nr
] &= ~(1U << bitnr
);
530 nr
= (replay_esn
->replay_window
- 1) >> 5;
531 for (i
= 0; i
<= nr
; i
++)
532 replay_esn
->bmp
[i
] = 0;
535 bitnr
= (pos
+ diff
) % replay_esn
->replay_window
;
536 replay_esn
->seq
= seq
;
538 if (unlikely(wrap
> 0))
539 replay_esn
->seq_hi
++;
541 diff
= replay_esn
->seq
- seq
;
544 bitnr
= (pos
- diff
) % replay_esn
->replay_window
;
546 bitnr
= replay_esn
->replay_window
- (diff
- pos
);
550 bitnr
= bitnr
& 0x1F;
551 replay_esn
->bmp
[nr
] |= (1U << bitnr
);
553 if (xfrm_aevent_is_on(xs_net(x
)))
554 x
->repl
->notify(x
, XFRM_REPLAY_UPDATE
);
557 static struct xfrm_replay xfrm_replay_legacy
= {
558 .advance
= xfrm_replay_advance
,
559 .check
= xfrm_replay_check
,
560 .recheck
= xfrm_replay_check
,
561 .notify
= xfrm_replay_notify
,
562 .overflow
= xfrm_replay_overflow
,
565 static struct xfrm_replay xfrm_replay_bmp
= {
566 .advance
= xfrm_replay_advance_bmp
,
567 .check
= xfrm_replay_check_bmp
,
568 .recheck
= xfrm_replay_check_bmp
,
569 .notify
= xfrm_replay_notify_bmp
,
570 .overflow
= xfrm_replay_overflow_bmp
,
573 static struct xfrm_replay xfrm_replay_esn
= {
574 .advance
= xfrm_replay_advance_esn
,
575 .check
= xfrm_replay_check_esn
,
576 .recheck
= xfrm_replay_recheck_esn
,
577 .notify
= xfrm_replay_notify_esn
,
578 .overflow
= xfrm_replay_overflow_esn
,
581 int xfrm_init_replay(struct xfrm_state
*x
)
583 struct xfrm_replay_state_esn
*replay_esn
= x
->replay_esn
;
586 if (replay_esn
->replay_window
>
587 replay_esn
->bmp_len
* sizeof(__u32
) * 8)
590 if (x
->props
.flags
& XFRM_STATE_ESN
) {
591 if (replay_esn
->replay_window
== 0)
593 x
->repl
= &xfrm_replay_esn
;
595 x
->repl
= &xfrm_replay_bmp
;
597 x
->repl
= &xfrm_replay_legacy
;
601 EXPORT_SYMBOL(xfrm_init_replay
);