aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorSteffen Klassert <steffen.klassert@secunet.com>2013-03-11 05:32:16 -0400
committerSteffen Klassert <steffen.klassert@secunet.com>2013-03-20 06:57:52 -0400
commit0017c0b57500606aab894cdb02fdf3380ddd60ee (patch)
tree79be87abec387e4f8e6a24afb16ea822e54e4938 /net
parent85dfb745ee40232876663ae206cba35f24ab2a40 (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.c68
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
337static 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
337static int xfrm_replay_overflow_esn(struct xfrm_state *x, struct sk_buff *skb) 403static 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