diff options
author | Steffen Klassert <steffen.klassert@secunet.com> | 2013-03-11 05:32:16 -0400 |
---|---|---|
committer | Steffen Klassert <steffen.klassert@secunet.com> | 2013-03-20 06:57:52 -0400 |
commit | 0017c0b57500606aab894cdb02fdf3380ddd60ee (patch) | |
tree | 79be87abec387e4f8e6a24afb16ea822e54e4938 /net | |
parent | 85dfb745ee40232876663ae206cba35f24ab2a40 (diff) |
xfrm: Fix replay notification for esn.
We may miscalculate the sequence number difference from the
last time we send a notification if a sequence number wrap
occured in the meantime. We fix this by adding a separate
replay notify function for esn. Here we take the high bits
of the sequence number into account to calculate the
difference.
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/xfrm/xfrm_replay.c | 68 |
1 files changed, 67 insertions, 1 deletions
diff --git a/net/xfrm/xfrm_replay.c b/net/xfrm/xfrm_replay.c index 35754cc8a9e5..a3906737f49e 100644 --- a/net/xfrm/xfrm_replay.c +++ b/net/xfrm/xfrm_replay.c | |||
@@ -334,6 +334,72 @@ static void xfrm_replay_notify_bmp(struct xfrm_state *x, int event) | |||
334 | x->xflags &= ~XFRM_TIME_DEFER; | 334 | x->xflags &= ~XFRM_TIME_DEFER; |
335 | } | 335 | } |
336 | 336 | ||
337 | static void xfrm_replay_notify_esn(struct xfrm_state *x, int event) | ||
338 | { | ||
339 | u32 seq_diff, oseq_diff; | ||
340 | struct km_event c; | ||
341 | struct xfrm_replay_state_esn *replay_esn = x->replay_esn; | ||
342 | struct xfrm_replay_state_esn *preplay_esn = x->preplay_esn; | ||
343 | |||
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 | ||
350 | * | ||
351 | * The state structure must be locked! | ||
352 | */ | ||
353 | |||
354 | switch (event) { | ||
355 | case XFRM_REPLAY_UPDATE: | ||
356 | if (!x->replay_maxdiff) | ||
357 | break; | ||
358 | |||
359 | if (replay_esn->seq_hi == preplay_esn->seq_hi) | ||
360 | seq_diff = replay_esn->seq - preplay_esn->seq; | ||
361 | else | ||
362 | seq_diff = UINT_MAX - preplay_esn->seq | ||
363 | + replay_esn->seq; | ||
364 | |||
365 | if (replay_esn->oseq_hi == preplay_esn->oseq_hi) | ||
366 | oseq_diff = replay_esn->oseq - preplay_esn->oseq; | ||
367 | else | ||
368 | oseq_diff = UINT_MAX - preplay_esn->oseq | ||
369 | + replay_esn->oseq; | ||
370 | |||
371 | if (seq_diff < x->replay_maxdiff && | ||
372 | oseq_diff < x->replay_maxdiff) { | ||
373 | |||
374 | if (x->xflags & XFRM_TIME_DEFER) | ||
375 | event = XFRM_REPLAY_TIMEOUT; | ||
376 | else | ||
377 | return; | ||
378 | } | ||
379 | |||
380 | break; | ||
381 | |||
382 | case XFRM_REPLAY_TIMEOUT: | ||
383 | if (memcmp(x->replay_esn, x->preplay_esn, | ||
384 | xfrm_replay_state_esn_len(replay_esn)) == 0) { | ||
385 | x->xflags |= XFRM_TIME_DEFER; | ||
386 | return; | ||
387 | } | ||
388 | |||
389 | break; | ||
390 | } | ||
391 | |||
392 | memcpy(x->preplay_esn, x->replay_esn, | ||
393 | xfrm_replay_state_esn_len(replay_esn)); | ||
394 | c.event = XFRM_MSG_NEWAE; | ||
395 | c.data.aevent = event; | ||
396 | km_state_notify(x, &c); | ||
397 | |||
398 | if (x->replay_maxage && | ||
399 | !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) | ||
400 | x->xflags &= ~XFRM_TIME_DEFER; | ||
401 | } | ||
402 | |||
337 | static int xfrm_replay_overflow_esn(struct xfrm_state *x, struct sk_buff *skb) | 403 | static int xfrm_replay_overflow_esn(struct xfrm_state *x, struct sk_buff *skb) |
338 | { | 404 | { |
339 | int err = 0; | 405 | int err = 0; |
@@ -510,7 +576,7 @@ static struct xfrm_replay xfrm_replay_esn = { | |||
510 | .advance = xfrm_replay_advance_esn, | 576 | .advance = xfrm_replay_advance_esn, |
511 | .check = xfrm_replay_check_esn, | 577 | .check = xfrm_replay_check_esn, |
512 | .recheck = xfrm_replay_recheck_esn, | 578 | .recheck = xfrm_replay_recheck_esn, |
513 | .notify = xfrm_replay_notify_bmp, | 579 | .notify = xfrm_replay_notify_esn, |
514 | .overflow = xfrm_replay_overflow_esn, | 580 | .overflow = xfrm_replay_overflow_esn, |
515 | }; | 581 | }; |
516 | 582 | ||