Blame view

net/xfrm/xfrm_replay.c 12.3 KB
9fdc4883d   Steffen Klassert   xfrm: Move IPsec ...
1
2
  /*
   * xfrm_replay.c - xfrm replay detection, derived from xfrm_state.c.
97e15c3a8   Steffen Klassert   xfrm: Support ant...
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
   *
   * Copyright (C) 2010 secunet Security Networks AG
   * Copyright (C) 2010 Steffen Klassert <steffen.klassert@secunet.com>
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms and conditions of the GNU General Public License,
   * version 2, as published by the Free Software Foundation.
   *
   * This program is distributed in the hope it will be useful, but WITHOUT
   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   * more details.
   *
   * You should have received a copy of the GNU General Public License along with
   * this program; if not, write to the Free Software Foundation, Inc.,
   * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
9fdc4883d   Steffen Klassert   xfrm: Move IPsec ...
19
   */
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
20
  #include <linux/export.h>
9fdc4883d   Steffen Klassert   xfrm: Move IPsec ...
21
  #include <net/xfrm.h>
2cd084678   Steffen Klassert   xfrm: Add support...
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
  u32 xfrm_replay_seqhi(struct xfrm_state *x, __be32 net_seq)
  {
  	u32 seq, seq_hi, bottom;
  	struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
  
  	if (!(x->props.flags & XFRM_STATE_ESN))
  		return 0;
  
  	seq = ntohl(net_seq);
  	seq_hi = replay_esn->seq_hi;
  	bottom = replay_esn->seq - replay_esn->replay_window + 1;
  
  	if (likely(replay_esn->seq >= replay_esn->replay_window - 1)) {
  		/* A. same subspace */
  		if (unlikely(seq < bottom))
  			seq_hi++;
  	} else {
  		/* B. window spans two subspaces */
  		if (unlikely(seq >= bottom))
  			seq_hi--;
  	}
  
  	return seq_hi;
  }
9fdc4883d   Steffen Klassert   xfrm: Move IPsec ...
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
  static void xfrm_replay_notify(struct xfrm_state *x, int event)
  {
  	struct km_event c;
  	/* we send notify messages in case
  	 *  1. we updated on of the sequence numbers, and the seqno difference
  	 *     is at least x->replay_maxdiff, in this case we also update the
  	 *     timeout of our timer function
  	 *  2. if x->replay_maxage has elapsed since last update,
  	 *     and there were changes
  	 *
  	 *  The state structure must be locked!
  	 */
  
  	switch (event) {
  	case XFRM_REPLAY_UPDATE:
  		if (x->replay_maxdiff &&
  		    (x->replay.seq - x->preplay.seq < x->replay_maxdiff) &&
  		    (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff)) {
  			if (x->xflags & XFRM_TIME_DEFER)
  				event = XFRM_REPLAY_TIMEOUT;
  			else
  				return;
  		}
  
  		break;
  
  	case XFRM_REPLAY_TIMEOUT:
  		if (memcmp(&x->replay, &x->preplay,
  			   sizeof(struct xfrm_replay_state)) == 0) {
  			x->xflags |= XFRM_TIME_DEFER;
  			return;
  		}
  
  		break;
  	}
  
  	memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state));
  	c.event = XFRM_MSG_NEWAE;
  	c.data.aevent = event;
  	km_state_notify(x, &c);
  
  	if (x->replay_maxage &&
  	    !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
  		x->xflags &= ~XFRM_TIME_DEFER;
  }
  
  static int xfrm_replay_overflow(struct xfrm_state *x, struct sk_buff *skb)
  {
  	int err = 0;
  	struct net *net = xs_net(x);
  
  	if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
  		XFRM_SKB_CB(skb)->seq.output.low = ++x->replay.oseq;
  		if (unlikely(x->replay.oseq == 0)) {
  			x->replay.oseq--;
  			xfrm_audit_state_replay_overflow(x, skb);
  			err = -EOVERFLOW;
  
  			return err;
  		}
  		if (xfrm_aevent_is_on(net))
  			x->repl->notify(x, XFRM_REPLAY_UPDATE);
  	}
  
  	return err;
  }
  
  static int xfrm_replay_check(struct xfrm_state *x,
  		      struct sk_buff *skb, __be32 net_seq)
  {
  	u32 diff;
  	u32 seq = ntohl(net_seq);
36ae0148d   Steffen Klassert   xfrm: Move the te...
118
119
  	if (!x->props.replay_window)
  		return 0;
9fdc4883d   Steffen Klassert   xfrm: Move IPsec ...
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
  	if (unlikely(seq == 0))
  		goto err;
  
  	if (likely(seq > x->replay.seq))
  		return 0;
  
  	diff = x->replay.seq - seq;
  	if (diff >= min_t(unsigned int, x->props.replay_window,
  			  sizeof(x->replay.bitmap) * 8)) {
  		x->stats.replay_window++;
  		goto err;
  	}
  
  	if (x->replay.bitmap & (1U << diff)) {
  		x->stats.replay++;
  		goto err;
  	}
  	return 0;
  
  err:
  	xfrm_audit_state_replay(x, skb, net_seq);
  	return -EINVAL;
  }
  
  static void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
  {
  	u32 diff;
  	u32 seq = ntohl(net_seq);
  
  	if (!x->props.replay_window)
  		return;
  
  	if (seq > x->replay.seq) {
  		diff = seq - x->replay.seq;
  		if (diff < x->props.replay_window)
  			x->replay.bitmap = ((x->replay.bitmap) << diff) | 1;
  		else
  			x->replay.bitmap = 1;
  		x->replay.seq = seq;
  	} else {
  		diff = x->replay.seq - seq;
  		x->replay.bitmap |= (1U << diff);
  	}
  
  	if (xfrm_aevent_is_on(xs_net(x)))
  		xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
  }
97e15c3a8   Steffen Klassert   xfrm: Support ant...
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
  static int xfrm_replay_overflow_bmp(struct xfrm_state *x, struct sk_buff *skb)
  {
  	int err = 0;
  	struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
  	struct net *net = xs_net(x);
  
  	if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
  		XFRM_SKB_CB(skb)->seq.output.low = ++replay_esn->oseq;
  		if (unlikely(replay_esn->oseq == 0)) {
  			replay_esn->oseq--;
  			xfrm_audit_state_replay_overflow(x, skb);
  			err = -EOVERFLOW;
  
  			return err;
  		}
  		if (xfrm_aevent_is_on(net))
  			x->repl->notify(x, XFRM_REPLAY_UPDATE);
  	}
  
  	return err;
  }
  
  static int xfrm_replay_check_bmp(struct xfrm_state *x,
  				 struct sk_buff *skb, __be32 net_seq)
  {
  	unsigned int bitnr, nr;
  	struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
36ae0148d   Steffen Klassert   xfrm: Move the te...
194
  	u32 pos;
97e15c3a8   Steffen Klassert   xfrm: Support ant...
195
196
  	u32 seq = ntohl(net_seq);
  	u32 diff =  replay_esn->seq - seq;
36ae0148d   Steffen Klassert   xfrm: Move the te...
197
198
199
  
  	if (!replay_esn->replay_window)
  		return 0;
97e15c3a8   Steffen Klassert   xfrm: Support ant...
200
201
202
203
204
205
206
207
208
209
  	if (unlikely(seq == 0))
  		goto err;
  
  	if (likely(seq > replay_esn->seq))
  		return 0;
  
  	if (diff >= replay_esn->replay_window) {
  		x->stats.replay_window++;
  		goto err;
  	}
1d9743745   Steffen Klassert   xfrm: Simplify th...
210
211
212
  	pos = (replay_esn->seq - 1) % replay_esn->replay_window;
  
  	if (pos >= diff)
97e15c3a8   Steffen Klassert   xfrm: Support ant...
213
  		bitnr = (pos - diff) % replay_esn->replay_window;
1d9743745   Steffen Klassert   xfrm: Simplify th...
214
  	else
97e15c3a8   Steffen Klassert   xfrm: Support ant...
215
  		bitnr = replay_esn->replay_window - (diff - pos);
1d9743745   Steffen Klassert   xfrm: Simplify th...
216
217
218
219
220
  
  	nr = bitnr >> 5;
  	bitnr = bitnr & 0x1F;
  	if (replay_esn->bmp[nr] & (1U << bitnr))
  		goto err_replay;
97e15c3a8   Steffen Klassert   xfrm: Support ant...
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
  	return 0;
  
  err_replay:
  	x->stats.replay++;
  err:
  	xfrm_audit_state_replay(x, skb, net_seq);
  	return -EINVAL;
  }
  
  static void xfrm_replay_advance_bmp(struct xfrm_state *x, __be32 net_seq)
  {
  	unsigned int bitnr, nr, i;
  	u32 diff;
  	struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
  	u32 seq = ntohl(net_seq);
  	u32 pos = (replay_esn->seq - 1) % replay_esn->replay_window;
  
  	if (!replay_esn->replay_window)
  		return;
  
  	if (seq > replay_esn->seq) {
  		diff = seq - replay_esn->seq;
  
  		if (diff < replay_esn->replay_window) {
  			for (i = 1; i < diff; i++) {
  				bitnr = (pos + i) % replay_esn->replay_window;
  				nr = bitnr >> 5;
  				bitnr = bitnr & 0x1F;
  				replay_esn->bmp[nr] &=  ~(1U << bitnr);
  			}
97e15c3a8   Steffen Klassert   xfrm: Support ant...
251
  		} else {
e756682c8   Steffen Klassert   xfrm: Fix off by ...
252
  			nr = (replay_esn->replay_window - 1) >> 5;
97e15c3a8   Steffen Klassert   xfrm: Support ant...
253
254
  			for (i = 0; i <= nr; i++)
  				replay_esn->bmp[i] = 0;
97e15c3a8   Steffen Klassert   xfrm: Support ant...
255
  		}
1d9743745   Steffen Klassert   xfrm: Simplify th...
256
  		bitnr = (pos + diff) % replay_esn->replay_window;
97e15c3a8   Steffen Klassert   xfrm: Support ant...
257
258
259
  		replay_esn->seq = seq;
  	} else {
  		diff = replay_esn->seq - seq;
1d9743745   Steffen Klassert   xfrm: Simplify th...
260
  		if (pos >= diff)
97e15c3a8   Steffen Klassert   xfrm: Support ant...
261
  			bitnr = (pos - diff) % replay_esn->replay_window;
1d9743745   Steffen Klassert   xfrm: Simplify th...
262
  		else
97e15c3a8   Steffen Klassert   xfrm: Support ant...
263
  			bitnr = replay_esn->replay_window - (diff - pos);
97e15c3a8   Steffen Klassert   xfrm: Support ant...
264
  	}
1d9743745   Steffen Klassert   xfrm: Simplify th...
265
266
267
  	nr = bitnr >> 5;
  	bitnr = bitnr & 0x1F;
  	replay_esn->bmp[nr] |= (1U << bitnr);
97e15c3a8   Steffen Klassert   xfrm: Support ant...
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
  	if (xfrm_aevent_is_on(xs_net(x)))
  		xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
  }
  
  static void xfrm_replay_notify_bmp(struct xfrm_state *x, int event)
  {
  	struct km_event c;
  	struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
  	struct xfrm_replay_state_esn *preplay_esn = x->preplay_esn;
  
  	/* we send notify messages in case
  	 *  1. we updated on of the sequence numbers, and the seqno difference
  	 *     is at least x->replay_maxdiff, in this case we also update the
  	 *     timeout of our timer function
  	 *  2. if x->replay_maxage has elapsed since last update,
  	 *     and there were changes
  	 *
  	 *  The state structure must be locked!
  	 */
  
  	switch (event) {
  	case XFRM_REPLAY_UPDATE:
  		if (x->replay_maxdiff &&
  		    (replay_esn->seq - preplay_esn->seq < x->replay_maxdiff) &&
  		    (replay_esn->oseq - preplay_esn->oseq < x->replay_maxdiff)) {
  			if (x->xflags & XFRM_TIME_DEFER)
  				event = XFRM_REPLAY_TIMEOUT;
  			else
  				return;
  		}
  
  		break;
  
  	case XFRM_REPLAY_TIMEOUT:
  		if (memcmp(x->replay_esn, x->preplay_esn,
  			   xfrm_replay_state_esn_len(replay_esn)) == 0) {
  			x->xflags |= XFRM_TIME_DEFER;
  			return;
  		}
  
  		break;
  	}
  
  	memcpy(x->preplay_esn, x->replay_esn,
  	       xfrm_replay_state_esn_len(replay_esn));
  	c.event = XFRM_MSG_NEWAE;
  	c.data.aevent = event;
  	km_state_notify(x, &c);
  
  	if (x->replay_maxage &&
  	    !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
  		x->xflags &= ~XFRM_TIME_DEFER;
  }
2cd084678   Steffen Klassert   xfrm: Add support...
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
  static int xfrm_replay_overflow_esn(struct xfrm_state *x, struct sk_buff *skb)
  {
  	int err = 0;
  	struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
  	struct net *net = xs_net(x);
  
  	if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
  		XFRM_SKB_CB(skb)->seq.output.low = ++replay_esn->oseq;
  		XFRM_SKB_CB(skb)->seq.output.hi = replay_esn->oseq_hi;
  
  		if (unlikely(replay_esn->oseq == 0)) {
  			XFRM_SKB_CB(skb)->seq.output.hi = ++replay_esn->oseq_hi;
  
  			if (replay_esn->oseq_hi == 0) {
  				replay_esn->oseq--;
  				replay_esn->oseq_hi--;
  				xfrm_audit_state_replay_overflow(x, skb);
  				err = -EOVERFLOW;
  
  				return err;
  			}
  		}
  		if (xfrm_aevent_is_on(net))
  			x->repl->notify(x, XFRM_REPLAY_UPDATE);
  	}
  
  	return err;
  }
  
  static int xfrm_replay_check_esn(struct xfrm_state *x,
  				 struct sk_buff *skb, __be32 net_seq)
  {
  	unsigned int bitnr, nr;
  	u32 diff;
  	struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
36ae0148d   Steffen Klassert   xfrm: Move the te...
356
  	u32 pos;
2cd084678   Steffen Klassert   xfrm: Add support...
357
  	u32 seq = ntohl(net_seq);
2cd084678   Steffen Klassert   xfrm: Add support...
358
359
360
  	u32 wsize = replay_esn->replay_window;
  	u32 top = replay_esn->seq;
  	u32 bottom = top - wsize + 1;
36ae0148d   Steffen Klassert   xfrm: Move the te...
361
362
  	if (!wsize)
  		return 0;
2cd084678   Steffen Klassert   xfrm: Add support...
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
  	if (unlikely(seq == 0 && replay_esn->seq_hi == 0 &&
  		     (replay_esn->seq < replay_esn->replay_window - 1)))
  		goto err;
  
  	diff = top - seq;
  
  	if (likely(top >= wsize - 1)) {
  		/* A. same subspace */
  		if (likely(seq > top) || seq < bottom)
  			return 0;
  	} else {
  		/* B. window spans two subspaces */
  		if (likely(seq > top && seq < bottom))
  			return 0;
  		if (seq >= bottom)
  			diff = ~seq + top + 1;
  	}
  
  	if (diff >= replay_esn->replay_window) {
  		x->stats.replay_window++;
  		goto err;
  	}
1d9743745   Steffen Klassert   xfrm: Simplify th...
385
386
387
  	pos = (replay_esn->seq - 1) % replay_esn->replay_window;
  
  	if (pos >= diff)
2cd084678   Steffen Klassert   xfrm: Add support...
388
  		bitnr = (pos - diff) % replay_esn->replay_window;
1d9743745   Steffen Klassert   xfrm: Simplify th...
389
  	else
2cd084678   Steffen Klassert   xfrm: Add support...
390
  		bitnr = replay_esn->replay_window - (diff - pos);
1d9743745   Steffen Klassert   xfrm: Simplify th...
391
392
393
394
395
  
  	nr = bitnr >> 5;
  	bitnr = bitnr & 0x1F;
  	if (replay_esn->bmp[nr] & (1U << bitnr))
  		goto err_replay;
2cd084678   Steffen Klassert   xfrm: Add support...
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
  	return 0;
  
  err_replay:
  	x->stats.replay++;
  err:
  	xfrm_audit_state_replay(x, skb, net_seq);
  	return -EINVAL;
  }
  
  static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq)
  {
  	unsigned int bitnr, nr, i;
  	int wrap;
  	u32 diff, pos, seq, seq_hi;
  	struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
  
  	if (!replay_esn->replay_window)
  		return;
  
  	seq = ntohl(net_seq);
  	pos = (replay_esn->seq - 1) % replay_esn->replay_window;
  	seq_hi = xfrm_replay_seqhi(x, net_seq);
  	wrap = seq_hi - replay_esn->seq_hi;
  
  	if ((!wrap && seq > replay_esn->seq) || wrap > 0) {
  		if (likely(!wrap))
  			diff = seq - replay_esn->seq;
  		else
  			diff = ~replay_esn->seq + seq + 1;
  
  		if (diff < replay_esn->replay_window) {
  			for (i = 1; i < diff; i++) {
  				bitnr = (pos + i) % replay_esn->replay_window;
  				nr = bitnr >> 5;
  				bitnr = bitnr & 0x1F;
  				replay_esn->bmp[nr] &=  ~(1U << bitnr);
  			}
2cd084678   Steffen Klassert   xfrm: Add support...
433
  		} else {
e756682c8   Steffen Klassert   xfrm: Fix off by ...
434
  			nr = (replay_esn->replay_window - 1) >> 5;
2cd084678   Steffen Klassert   xfrm: Add support...
435
436
  			for (i = 0; i <= nr; i++)
  				replay_esn->bmp[i] = 0;
2cd084678   Steffen Klassert   xfrm: Add support...
437
  		}
1d9743745   Steffen Klassert   xfrm: Simplify th...
438
  		bitnr = (pos + diff) % replay_esn->replay_window;
2cd084678   Steffen Klassert   xfrm: Add support...
439
440
441
442
443
444
  		replay_esn->seq = seq;
  
  		if (unlikely(wrap > 0))
  			replay_esn->seq_hi++;
  	} else {
  		diff = replay_esn->seq - seq;
1d9743745   Steffen Klassert   xfrm: Simplify th...
445
  		if (pos >= diff)
2cd084678   Steffen Klassert   xfrm: Add support...
446
  			bitnr = (pos - diff) % replay_esn->replay_window;
1d9743745   Steffen Klassert   xfrm: Simplify th...
447
  		else
2cd084678   Steffen Klassert   xfrm: Add support...
448
  			bitnr = replay_esn->replay_window - (diff - pos);
2cd084678   Steffen Klassert   xfrm: Add support...
449
  	}
1d9743745   Steffen Klassert   xfrm: Simplify th...
450
451
452
  	nr = bitnr >> 5;
  	bitnr = bitnr & 0x1F;
  	replay_esn->bmp[nr] |= (1U << bitnr);
2cd084678   Steffen Klassert   xfrm: Add support...
453
454
455
  	if (xfrm_aevent_is_on(xs_net(x)))
  		xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
  }
9fdc4883d   Steffen Klassert   xfrm: Move IPsec ...
456
457
458
459
460
461
  static struct xfrm_replay xfrm_replay_legacy = {
  	.advance	= xfrm_replay_advance,
  	.check		= xfrm_replay_check,
  	.notify		= xfrm_replay_notify,
  	.overflow	= xfrm_replay_overflow,
  };
97e15c3a8   Steffen Klassert   xfrm: Support ant...
462
463
464
465
466
467
  static struct xfrm_replay xfrm_replay_bmp = {
  	.advance	= xfrm_replay_advance_bmp,
  	.check		= xfrm_replay_check_bmp,
  	.notify		= xfrm_replay_notify_bmp,
  	.overflow	= xfrm_replay_overflow_bmp,
  };
2cd084678   Steffen Klassert   xfrm: Add support...
468
469
470
471
472
473
  static struct xfrm_replay xfrm_replay_esn = {
  	.advance	= xfrm_replay_advance_esn,
  	.check		= xfrm_replay_check_esn,
  	.notify		= xfrm_replay_notify_bmp,
  	.overflow	= xfrm_replay_overflow_esn,
  };
9fdc4883d   Steffen Klassert   xfrm: Move IPsec ...
474
475
  int xfrm_init_replay(struct xfrm_state *x)
  {
97e15c3a8   Steffen Klassert   xfrm: Support ant...
476
477
478
479
  	struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
  
  	if (replay_esn) {
  		if (replay_esn->replay_window >
3f602b08d   Steffen Klassert   xfrm: Fix replay ...
480
  		    replay_esn->bmp_len * sizeof(__u32) * 8)
97e15c3a8   Steffen Klassert   xfrm: Support ant...
481
  			return -EINVAL;
6fa5ddcc6   Steffen Klassert   xfrm: Don't allow...
482
483
  	if ((x->props.flags & XFRM_STATE_ESN) && replay_esn->replay_window == 0)
  		return -EINVAL;
2cd084678   Steffen Klassert   xfrm: Add support...
484
485
486
  	if ((x->props.flags & XFRM_STATE_ESN) && x->replay_esn)
  		x->repl = &xfrm_replay_esn;
  	else
97e15c3a8   Steffen Klassert   xfrm: Support ant...
487
488
489
  		x->repl = &xfrm_replay_bmp;
  	} else
  		x->repl = &xfrm_replay_legacy;
9fdc4883d   Steffen Klassert   xfrm: Move IPsec ...
490
491
492
  	return 0;
  }
  EXPORT_SYMBOL(xfrm_init_replay);