xref: /aosp_15_r20/external/libnl/lib/xfrm/ae.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
4  *
5  *
6  *  Redistribution and use in source and binary forms, with or without
7  *  modification, are permitted provided that the following conditions
8  *  are met:
9  *
10  *    Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  *    Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the
16  *    distribution.
17  *
18  *    Neither the name of Texas Instruments Incorporated nor the names of
19  *    its contributors may be used to endorse or promote products derived
20  *    from this software without specific prior written permission.
21  *
22  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  */
35 
36 /**
37  * @ingroup xfrmnl
38  * @defgroup ae Attribute Element
39  * @brief
40  *
41  * The AE interface allows a user to retrieve and update various
42  * Security Association (SA) attributes such as lifetime, replay state etc.
43  *
44  * @par AE Flags
45  * @code
46  * XFRM_AE_UNSPEC
47  * XFRM_AE_RTHR=1
48  * XFRM_AE_RVAL=2
49  * XFRM_AE_LVAL=4
50  * XFRM_AE_ETHR=8
51  * XFRM_AE_CR=16
52  * XFRM_AE_CE=32
53  * XFRM_AE_CU=64
54  * @endcode
55  *
56  * @par AE Identification
57  * An AE is uniquely identified by the attributes listed below, whenever
58  * you refer to an existing AE all of the attributes must be set. There is
59  * no cache support for AE since you can retrieve the AE for any given combination
60  * of attributes mentioned below, but not all at once since they just characterize
61  * an SA.
62  *   - destination address (xfrmnl_ae_set_daddr())
63  *   - SPI (xfrmnl_ae_set_spi)
64  *   - protocol (xfrmnl_ae_set_proto)
65  *   - mark (xfrmnl_ae_set_mark)
66  *
67  * @par Changeable Attributes
68  * \anchor ae_changeable
69  *  - current lifetime (xfrmnl_ae_set_curlifetime())
70  *  - replay properties (xfrmnl_ae_set_replay_maxage(), xfrmnl_ae_set_replay_maxdiff())
71  *  - replay state (xfrmnl_ae_set_replay_state(), xfrmnl_ae_set_replay_state_esn))
72  *
73  * @par Required Caches for Dumping
74  * None
75  *
76  * @par TODO
77  * None
78  *
79  * @par 1) Retrieving AE information for a given SA tuple
80  * @code
81  * // Create a netlink socket and connect it to XFRM subsystem in
82  * the kernel to be able to send/receive info from userspace.
83  * struct nl_sock* sk = nl_socket_alloc ();
84  * nl_connect (sk, NETLINK_XFRM);
85  *
86  * // AEs can then be looked up by the SA tuple, destination address,
87  * SPI, protocol, mark:
88  * struct xfrmnl_ae *ae;
89  * xfrmnl_ae_get_kernel(sk, dst_addr, spi, proto,mark_mask, mark_value, &ae);
90  *
91  * // After successful usage, the object must be freed
92  * xfrmnl_ae_put(ae);
93  * @endcode
94  *
95  * @par 2) Updating AE
96  * @code
97  * // Allocate an empty AE handle to be filled out with the attributes
98  * // of the new AE.
99  * struct xfrmnl_ae *ae = xfrmnl_ae_alloc();
100  *
101  * // Fill out the attributes of the new AE
102  * xfrmnl_ae_set_daddr(ae, dst_addr);
103  * xfrmnl_ae_set_spi(ae, 0xDEADBEEF);
104  * xfrmnl_ae_set_proto(ae, 50);
105  * xfrmnl_ae_set_mark(ae, 0x0);
106  * xfrmnl_ae_set_saddr(ae, src_addr);
107  * xfrmnl_ae_set_curlifetime(ae, 540, 10, 0xAABB1122, 0x0);
108  *
109  * // Build the netlink message and send it to the kernel, the operation will
110  * // block until the operation has been completed. Alternatively, a netlink message
111  * // can be built using xfrmnl_ae_build_get_request () API and be sent using
112  * // nl_send_auto(). Further the result from the kernel can be parsed using
113  * // xfrmnl_ae_parse() API.
114  * xfrmnl_ae_set(sk, ae, NLM_F_REPLACE);
115  *
116  * // Free the memory
117  * xfrmnl_ae_put(ae);
118  * @endcode
119  *
120  * @{
121  */
122 
123 #include "nl-default.h"
124 
125 #include <time.h>
126 #include <linux/xfrm.h>
127 
128 #include <netlink/netlink.h>
129 #include <netlink/cache.h>
130 #include <netlink/object.h>
131 #include <netlink/xfrm/ae.h>
132 
133 #include "nl-xfrm.h"
134 #include "nl-priv-dynamic-core/object-api.h"
135 #include "nl-priv-dynamic-core/nl-core.h"
136 #include "nl-priv-dynamic-core/cache-api.h"
137 #include "nl-aux-core/nl-core.h"
138 #include "nl-aux-xfrm/nl-xfrm.h"
139 
140 /** @cond SKIP */
141 
142 struct xfrmnl_sa_id {
143 	struct nl_addr* daddr;
144 	uint32_t        spi;
145 	uint16_t        family;
146 	uint8_t         proto;
147 };
148 
149 struct xfrmnl_ae {
150 	NLHDR_COMMON
151 
152 	struct xfrmnl_sa_id             sa_id;
153 	struct nl_addr*                 saddr;
154 	uint32_t                        flags;
155 	uint32_t                        reqid;
156 	struct xfrmnl_mark              mark;
157 	struct xfrmnl_lifetime_cur      lifetime_cur;
158 	uint32_t                        replay_maxage;
159 	uint32_t                        replay_maxdiff;
160 	struct xfrmnl_replay_state      replay_state;
161 	struct xfrmnl_replay_state_esn* replay_state_esn;
162 };
163 
164 #define XFRM_AE_ATTR_DADDR          0x01
165 #define XFRM_AE_ATTR_SPI            0x02
166 #define XFRM_AE_ATTR_PROTO          0x04
167 #define XFRM_AE_ATTR_SADDR          0x08
168 #define XFRM_AE_ATTR_FLAGS          0x10
169 #define XFRM_AE_ATTR_REQID          0x20
170 #define XFRM_AE_ATTR_MARK           0x40
171 #define XFRM_AE_ATTR_LIFETIME       0x80
172 #define XFRM_AE_ATTR_REPLAY_MAXAGE  0x100
173 #define XFRM_AE_ATTR_REPLAY_MAXDIFF 0x200
174 #define XFRM_AE_ATTR_REPLAY_STATE   0x400
175 #define XFRM_AE_ATTR_FAMILY         0x800
176 
177 static struct nl_object_ops xfrm_ae_obj_ops;
178 /** @endcond */
179 
180 
xfrm_ae_free_data(struct nl_object * c)181 static void xfrm_ae_free_data(struct nl_object *c)
182 {
183 	struct xfrmnl_ae* ae =   nl_object_priv (c);
184 
185 	if (ae == NULL)
186 		return;
187 
188 	nl_addr_put (ae->sa_id.daddr);
189 	nl_addr_put (ae->saddr);
190 
191 	if (ae->replay_state_esn)
192 		free (ae->replay_state_esn);
193 }
194 
xfrm_ae_clone(struct nl_object * _dst,struct nl_object * _src)195 static int xfrm_ae_clone(struct nl_object *_dst, struct nl_object *_src)
196 {
197 	struct xfrmnl_ae* dst = nl_object_priv(_dst);
198 	struct xfrmnl_ae* src = nl_object_priv(_src);
199 
200 	dst->sa_id.daddr = NULL;
201 	dst->saddr = NULL;
202 	dst->replay_state_esn = NULL;
203 
204 	if (src->sa_id.daddr) {
205 		if ((dst->sa_id.daddr = nl_addr_clone (src->sa_id.daddr)) == NULL)
206 			return -NLE_NOMEM;
207 	}
208 
209 	if (src->saddr) {
210 		if ((dst->saddr = nl_addr_clone (src->saddr)) == NULL)
211 			return -NLE_NOMEM;
212 	}
213 
214 	if (src->replay_state_esn) {
215 		uint32_t len = sizeof (struct xfrmnl_replay_state_esn) + (sizeof (uint32_t) * src->replay_state_esn->bmp_len);
216 
217 		if ((dst->replay_state_esn = malloc (len)) == NULL)
218 			return -NLE_NOMEM;
219 		memcpy (dst->replay_state_esn, src->replay_state_esn, len);
220 	}
221 
222 	return 0;
223 }
224 
xfrm_ae_compare(struct nl_object * _a,struct nl_object * _b,uint64_t attrs,int flags)225 static uint64_t xfrm_ae_compare(struct nl_object *_a, struct nl_object *_b,
226 				uint64_t attrs, int flags)
227 {
228 	struct xfrmnl_ae* a  =   (struct xfrmnl_ae *) _a;
229 	struct xfrmnl_ae* b  =   (struct xfrmnl_ae *) _b;
230 	uint64_t diff = 0;
231 	int found = 0;
232 
233 #define _DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ATTR, a, b, EXPR)
234 	diff |= _DIFF(XFRM_AE_ATTR_DADDR,
235 		      nl_addr_cmp(a->sa_id.daddr, b->sa_id.daddr));
236 	diff |= _DIFF(XFRM_AE_ATTR_SPI, a->sa_id.spi != b->sa_id.spi);
237 	diff |= _DIFF(XFRM_AE_ATTR_PROTO, a->sa_id.proto != b->sa_id.proto);
238 	diff |= _DIFF(XFRM_AE_ATTR_SADDR, nl_addr_cmp(a->saddr, b->saddr));
239 	diff |= _DIFF(XFRM_AE_ATTR_FLAGS, a->flags != b->flags);
240 	diff |= _DIFF(XFRM_AE_ATTR_REQID, a->reqid != b->reqid);
241 	diff |= _DIFF(XFRM_AE_ATTR_MARK,
242 		      (a->mark.v & a->mark.m) != (b->mark.v & b->mark.m));
243 	diff |= _DIFF(XFRM_AE_ATTR_REPLAY_MAXAGE,
244 		      a->replay_maxage != b->replay_maxage);
245 	diff |= _DIFF(XFRM_AE_ATTR_REPLAY_MAXDIFF,
246 		      a->replay_maxdiff != b->replay_maxdiff);
247 
248 	/* Compare replay states */
249 	found = AVAILABLE_MISMATCH (a, b, XFRM_AE_ATTR_REPLAY_STATE);
250 	if (found == 0) // attribute exists in both objects
251 	{
252 		if (((a->replay_state_esn != NULL) && (b->replay_state_esn == NULL)) ||
253 			((a->replay_state_esn == NULL) && (b->replay_state_esn != NULL)))
254 			found |= 1;
255 
256 		if (found == 0) // same replay type. compare actual values
257 		{
258 			if (a->replay_state_esn)
259 			{
260 				if (a->replay_state_esn->bmp_len != b->replay_state_esn->bmp_len)
261 					diff |= 1;
262 				else
263 				{
264 					uint32_t len = sizeof (struct xfrmnl_replay_state_esn) + (sizeof (uint32_t) * a->replay_state_esn->bmp_len);
265 					diff |= memcmp (a->replay_state_esn, b->replay_state_esn, len);
266 				}
267 			}
268 			else
269 			{
270 				if ((a->replay_state.oseq != b->replay_state.oseq) ||
271 				    (a->replay_state.seq != b->replay_state.seq) ||
272 				    (a->replay_state.bitmap != b->replay_state.bitmap))
273 					diff |= 1;
274 			}
275 		}
276 	}
277 #undef _DIFF
278 
279 	return diff;
280 }
281 
282 /**
283  * @name XFRM AE Attribute Translations
284  * @{
285  */
286 static const struct trans_tbl ae_attrs[] =
287 {
288 	__ADD(XFRM_AE_ATTR_DADDR, daddr),
289 	__ADD(XFRM_AE_ATTR_SPI, spi),
290 	__ADD(XFRM_AE_ATTR_PROTO, protocol),
291 	__ADD(XFRM_AE_ATTR_SADDR, saddr),
292 	__ADD(XFRM_AE_ATTR_FLAGS, flags),
293 	__ADD(XFRM_AE_ATTR_REQID, reqid),
294 	__ADD(XFRM_AE_ATTR_MARK, mark),
295 	__ADD(XFRM_AE_ATTR_LIFETIME, cur_lifetime),
296 	__ADD(XFRM_AE_ATTR_REPLAY_MAXAGE, replay_maxage),
297 	__ADD(XFRM_AE_ATTR_REPLAY_MAXDIFF, replay_maxdiff),
298 	__ADD(XFRM_AE_ATTR_REPLAY_STATE, replay_state),
299 };
300 
xfrm_ae_attrs2str(int attrs,char * buf,size_t len)301 static char* xfrm_ae_attrs2str (int attrs, char *buf, size_t len)
302 {
303 	return __flags2str(attrs, buf, len, ae_attrs, ARRAY_SIZE(ae_attrs));
304 }
305 /** @} */
306 
307 /**
308  * @name XFRM AE Flags Translations
309  * @{
310  */
311 
312 static const struct trans_tbl ae_flags[] = {
313 	__ADD(XFRM_AE_UNSPEC, unspecified),
314 	__ADD(XFRM_AE_RTHR, replay threshold),
315 	__ADD(XFRM_AE_RVAL, replay value),
316 	__ADD(XFRM_AE_LVAL, lifetime value),
317 	__ADD(XFRM_AE_ETHR, expiry time threshold),
318 	__ADD(XFRM_AE_CR, replay update event),
319 	__ADD(XFRM_AE_CE, timer expiry event),
320 	__ADD(XFRM_AE_CU, policy update event),
321 };
322 
xfrmnl_ae_flags2str(int flags,char * buf,size_t len)323 char* xfrmnl_ae_flags2str(int flags, char *buf, size_t len)
324 {
325 	return __flags2str (flags, buf, len, ae_flags, ARRAY_SIZE(ae_flags));
326 }
327 
xfrmnl_ae_str2flag(const char * name)328 int xfrmnl_ae_str2flag(const char *name)
329 {
330 	return __str2flags(name, ae_flags, ARRAY_SIZE(ae_flags));
331 }
332 /** @} */
333 
xfrm_ae_dump_line(struct nl_object * a,struct nl_dump_params * p)334 static void xfrm_ae_dump_line(struct nl_object *a, struct nl_dump_params *p)
335 {
336 	char                dst[INET6_ADDRSTRLEN+5], src[INET6_ADDRSTRLEN+5];
337 	struct xfrmnl_ae*   ae  =   (struct xfrmnl_ae *) a;
338 	char                flags[128], buf[128];
339 	time_t              add_time, use_time;
340 	struct tm           *add_time_tm, *use_time_tm;
341 	struct tm           tm_buf;
342 
343 	nl_dump_line(p, "src %s dst %s \n", nl_addr2str(ae->saddr, src, sizeof(src)),
344 				nl_addr2str(ae->sa_id.daddr, dst, sizeof(dst)));
345 
346 	nl_dump_line(p, "\tproto %s spi 0x%x reqid %u ",
347 				nl_ip_proto2str (ae->sa_id.proto, buf, sizeof (buf)),
348 				ae->sa_id.spi, ae->reqid);
349 
350 	xfrmnl_ae_flags2str(ae->flags, flags, sizeof (flags));
351 	nl_dump_line(p, "flags %s(0x%x) mark mask/value 0x%x/0x%x \n", flags,
352 				ae->flags, ae->mark.m, ae->mark.v);
353 
354 	nl_dump_line(p, "\tlifetime current: \n");
355 	nl_dump_line(p, "\t\tbytes %llu packets %llu \n",
356 		     (long long unsigned)ae->lifetime_cur.bytes,
357 		     (long long unsigned)ae->lifetime_cur.packets);
358 	if (ae->lifetime_cur.add_time != 0)
359 	{
360 		add_time = ae->lifetime_cur.add_time;
361 		add_time_tm = gmtime_r (&add_time, &tm_buf);
362 		strftime (flags, 128, "%Y-%m-%d %H-%M-%S", add_time_tm);
363 	}
364 	else
365 	{
366 		sprintf (flags, "%s", "-");
367 	}
368 
369 	if (ae->lifetime_cur.use_time != 0)
370 	{
371 		use_time = ae->lifetime_cur.use_time;
372 		use_time_tm = gmtime_r (&use_time, &tm_buf);
373 		strftime (buf, 128, "%Y-%m-%d %H-%M-%S", use_time_tm);
374 	}
375 	else
376 	{
377 		sprintf (buf, "%s", "-");
378 	}
379 	nl_dump_line(p, "\t\tadd_time: %s, use_time: %s\n", flags, buf);
380 
381 	nl_dump_line(p, "\treplay info: \n");
382 	nl_dump_line(p, "\t\tmax age %u max diff %u \n", ae->replay_maxage, ae->replay_maxdiff);
383 
384 	nl_dump_line(p, "\treplay state info: \n");
385 	if (ae->replay_state_esn)
386 	{
387 		nl_dump_line(p, "\t\toseq %u seq %u oseq_hi %u seq_hi %u replay window: %u \n",
388 					ae->replay_state_esn->oseq, ae->replay_state_esn->seq,
389 					ae->replay_state_esn->oseq_hi, ae->replay_state_esn->seq_hi,
390 					ae->replay_state_esn->replay_window);
391 	}
392 	else
393 	{
394 		nl_dump_line(p, "\t\toseq %u seq %u bitmap: %u \n", ae->replay_state.oseq,
395 					ae->replay_state.seq, ae->replay_state.bitmap);
396 	}
397 
398 	nl_dump(p, "\n");
399 }
400 
xfrm_ae_dump_details(struct nl_object * a,struct nl_dump_params * p)401 static void xfrm_ae_dump_details(struct nl_object *a, struct nl_dump_params *p)
402 {
403 	xfrm_ae_dump_line(a, p);
404 }
405 
xfrm_ae_dump_stats(struct nl_object * a,struct nl_dump_params * p)406 static void xfrm_ae_dump_stats(struct nl_object *a, struct nl_dump_params *p)
407 {
408 	xfrm_ae_dump_details(a, p);
409 }
410 
411 
build_xfrm_ae_message(struct xfrmnl_ae * tmpl,int cmd,int flags,struct nl_msg ** result)412 static int build_xfrm_ae_message(struct xfrmnl_ae *tmpl, int cmd, int flags,
413 			   struct nl_msg **result)
414 {
415 	struct nl_msg*          msg;
416 	struct xfrm_aevent_id   ae_id;
417 
418 	if (!(tmpl->ce_mask & XFRM_AE_ATTR_DADDR) ||
419 		!(tmpl->ce_mask & XFRM_AE_ATTR_SPI) ||
420 		!(tmpl->ce_mask & XFRM_AE_ATTR_PROTO))
421 		return -NLE_MISSING_ATTR;
422 
423 	memset(&ae_id, 0, sizeof(ae_id));
424 
425 	memcpy (&ae_id.sa_id.daddr, nl_addr_get_binary_addr (tmpl->sa_id.daddr), sizeof (uint8_t) * nl_addr_get_len (tmpl->sa_id.daddr));
426 	ae_id.sa_id.spi    = htonl(tmpl->sa_id.spi);
427 	ae_id.sa_id.family = tmpl->sa_id.family;
428 	ae_id.sa_id.proto  = tmpl->sa_id.proto;
429 
430 	if (tmpl->ce_mask & XFRM_AE_ATTR_SADDR)
431 		memcpy (&ae_id.saddr, nl_addr_get_binary_addr (tmpl->saddr), sizeof (uint8_t) * nl_addr_get_len (tmpl->saddr));
432 
433 	if (tmpl->ce_mask & XFRM_AE_ATTR_FLAGS)
434 		ae_id.flags    = tmpl->flags;
435 
436 	if (tmpl->ce_mask & XFRM_AE_ATTR_REQID)
437 		ae_id.reqid    = tmpl->reqid;
438 
439 	msg = nlmsg_alloc_simple(cmd, flags);
440 	if (!msg)
441 		return -NLE_NOMEM;
442 
443 	if (nlmsg_append(msg, &ae_id, sizeof(ae_id), NLMSG_ALIGNTO) < 0)
444 		goto nla_put_failure;
445 
446 	if (tmpl->ce_mask & XFRM_AE_ATTR_MARK)
447 		NLA_PUT (msg, XFRMA_MARK, sizeof (struct xfrmnl_mark), &tmpl->mark);
448 
449 	if (tmpl->ce_mask & XFRM_AE_ATTR_LIFETIME)
450 		NLA_PUT (msg, XFRMA_LTIME_VAL, sizeof (struct xfrmnl_lifetime_cur), &tmpl->lifetime_cur);
451 
452 	if (tmpl->ce_mask & XFRM_AE_ATTR_REPLAY_MAXAGE)
453 		NLA_PUT_U32 (msg, XFRMA_ETIMER_THRESH, tmpl->replay_maxage);
454 
455 	if (tmpl->ce_mask & XFRM_AE_ATTR_REPLAY_MAXDIFF)
456 		NLA_PUT_U32 (msg, XFRMA_REPLAY_THRESH, tmpl->replay_maxdiff);
457 
458 	if (tmpl->ce_mask & XFRM_AE_ATTR_REPLAY_STATE) {
459 		if (tmpl->replay_state_esn) {
460 			uint32_t len = sizeof (struct xfrm_replay_state_esn) + (sizeof (uint32_t) * tmpl->replay_state_esn->bmp_len);
461 			NLA_PUT (msg, XFRMA_REPLAY_ESN_VAL, len, tmpl->replay_state_esn);
462 		}
463 		else {
464 			NLA_PUT (msg, XFRMA_REPLAY_VAL, sizeof (struct xfrmnl_replay_state), &tmpl->replay_state);
465 		}
466 	}
467 
468 	*result = msg;
469 	return 0;
470 
471 nla_put_failure:
472 	nlmsg_free(msg);
473 	return -NLE_MSGSIZE;
474 }
475 
476 /**
477  * @name XFRM AE Update
478  * @{
479  */
480 
xfrmnl_ae_set(struct nl_sock * sk,struct xfrmnl_ae * ae,int flags)481 int xfrmnl_ae_set(struct nl_sock* sk, struct xfrmnl_ae* ae, int flags)
482 {
483 	int err;
484 	struct nl_msg *msg;
485 
486 	if ((err = build_xfrm_ae_message(ae, XFRM_MSG_NEWAE, flags|NLM_F_REPLACE, &msg)) < 0)
487 		return err;
488 
489 	err = nl_send_auto_complete(sk, msg);
490 	nlmsg_free(msg);
491 	if (err < 0)
492 		return err;
493 
494 	return nl_wait_for_ack(sk);
495 }
496 
497 /** @} */
498 
499 /**
500  * @name XFRM AE Object Allocation/Freeage
501  * @{
502  */
503 
xfrmnl_ae_alloc(void)504 struct xfrmnl_ae* xfrmnl_ae_alloc(void)
505 {
506 	return (struct xfrmnl_ae*) nl_object_alloc(&xfrm_ae_obj_ops);
507 }
508 
xfrmnl_ae_put(struct xfrmnl_ae * ae)509 void xfrmnl_ae_put(struct xfrmnl_ae* ae)
510 {
511 	nl_object_put((struct nl_object *) ae);
512 }
513 
514 /** @} */
515 
516 static struct nla_policy xfrm_ae_policy[XFRMA_MAX+1] = {
517 	[XFRMA_LTIME_VAL]       = { .minlen = sizeof(struct xfrm_lifetime_cur) },
518 	[XFRMA_REPLAY_VAL]      = { .minlen = sizeof(struct xfrm_replay_state) },
519 	[XFRMA_REPLAY_THRESH]   = { .type = NLA_U32 },
520 	[XFRMA_ETIMER_THRESH]   = { .type = NLA_U32 },
521 	[XFRMA_SRCADDR]         = { .minlen = sizeof(xfrm_address_t) },
522 	[XFRMA_MARK]            = { .minlen = sizeof(struct xfrm_mark) },
523 	[XFRMA_REPLAY_ESN_VAL]  = { .minlen = sizeof(struct xfrm_replay_state_esn) },
524 };
525 
xfrmnl_ae_parse(struct nlmsghdr * n,struct xfrmnl_ae ** result)526 int xfrmnl_ae_parse(struct nlmsghdr *n, struct xfrmnl_ae **result)
527 {
528 	_nl_auto_xfrmnl_ae struct xfrmnl_ae *ae = NULL;
529 	struct nlattr           *tb[XFRMA_MAX + 1];
530 	struct xfrm_aevent_id*  ae_id;
531 	int err;
532 
533 	ae = xfrmnl_ae_alloc();
534 	if (!ae)
535 		return -NLE_NOMEM;
536 
537 	ae->ce_msgtype = n->nlmsg_type;
538 	ae_id = nlmsg_data(n);
539 
540 	err = nlmsg_parse(n, sizeof(struct xfrm_aevent_id), tb, XFRMA_MAX, xfrm_ae_policy);
541 	if (err < 0)
542 		return err;
543 
544 	if (!(ae->sa_id.daddr =
545 		      _nl_addr_build(ae_id->sa_id.family, &ae_id->sa_id.daddr)))
546 		return -NLE_NOMEM;
547 	ae->sa_id.family= ae_id->sa_id.family;
548 	ae->sa_id.spi   = ntohl(ae_id->sa_id.spi);
549 	ae->sa_id.proto = ae_id->sa_id.proto;
550 	if (!(ae->saddr = _nl_addr_build(ae_id->sa_id.family, &ae_id->saddr)))
551 		return -NLE_NOMEM;
552 	ae->reqid       = ae_id->reqid;
553 	ae->flags       = ae_id->flags;
554 	ae->ce_mask |= (XFRM_AE_ATTR_DADDR | XFRM_AE_ATTR_FAMILY | XFRM_AE_ATTR_SPI |
555 					XFRM_AE_ATTR_PROTO | XFRM_AE_ATTR_SADDR | XFRM_AE_ATTR_REQID |
556 					XFRM_AE_ATTR_FLAGS);
557 
558 	if (tb[XFRMA_MARK]) {
559 		struct xfrm_mark* m =   nla_data(tb[XFRMA_MARK]);
560 		ae->mark.m  =   m->m;
561 		ae->mark.v  =   m->v;
562 		ae->ce_mask |= XFRM_AE_ATTR_MARK;
563 	}
564 
565 	if (tb[XFRMA_LTIME_VAL]) {
566 		struct xfrm_lifetime_cur* cur =   nla_data(tb[XFRMA_LTIME_VAL]);
567 
568 		ae->lifetime_cur.bytes      =   cur->bytes;
569 		ae->lifetime_cur.packets    =   cur->packets;
570 		ae->lifetime_cur.add_time   =   cur->add_time;
571 		ae->lifetime_cur.use_time   =   cur->use_time;
572 		ae->ce_mask |= XFRM_AE_ATTR_LIFETIME;
573 	}
574 
575 	if (tb[XFRM_AE_ETHR]) {
576 		ae->replay_maxage       =   *(uint32_t*)nla_data(tb[XFRM_AE_ETHR]);
577 		ae->ce_mask |= XFRM_AE_ATTR_REPLAY_MAXAGE;
578 	}
579 
580 	if (tb[XFRM_AE_RTHR]) {
581 		ae->replay_maxdiff      =   *(uint32_t*)nla_data(tb[XFRM_AE_RTHR]);
582 		ae->ce_mask |= XFRM_AE_ATTR_REPLAY_MAXDIFF;
583 	}
584 
585 	if (tb[XFRMA_REPLAY_ESN_VAL]) {
586 		struct xfrm_replay_state_esn* esn =  nla_data (tb[XFRMA_REPLAY_ESN_VAL]);
587 		uint32_t len = sizeof (struct xfrmnl_replay_state_esn) +  (sizeof (uint32_t) * esn->bmp_len);
588 
589 		if ((ae->replay_state_esn = calloc (1, len)) == NULL)
590 			return -NLE_NOMEM;
591 		ae->replay_state_esn->oseq       =  esn->oseq;
592 		ae->replay_state_esn->seq        =  esn->seq;
593 		ae->replay_state_esn->oseq_hi    =  esn->oseq_hi;
594 		ae->replay_state_esn->seq_hi     =  esn->seq_hi;
595 		ae->replay_state_esn->replay_window   =   esn->replay_window;
596 		ae->replay_state_esn->bmp_len    =   esn->bmp_len;
597 		memcpy (ae->replay_state_esn->bmp, esn->bmp, sizeof (uint32_t) * esn->bmp_len);
598 		ae->ce_mask |= XFRM_AE_ATTR_REPLAY_STATE;
599 	}
600 	else
601 	{
602 		struct xfrm_replay_state* replay_state = nla_data (tb[XFRMA_REPLAY_VAL]);
603 		ae->replay_state.oseq       =   replay_state->oseq;
604 		ae->replay_state.seq        =   replay_state->seq;
605 		ae->replay_state.bitmap     =   replay_state->bitmap;
606 		ae->ce_mask |= XFRM_AE_ATTR_REPLAY_STATE;
607 
608 		ae->replay_state_esn = NULL;
609 	}
610 
611 	*result = _nl_steal_pointer(&ae);
612 	return 0;
613 }
614 
xfrm_ae_msg_parser(struct nl_cache_ops * ops,struct sockaddr_nl * who,struct nlmsghdr * n,struct nl_parser_param * pp)615 static int xfrm_ae_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
616 				struct nlmsghdr *n, struct nl_parser_param *pp)
617 {
618 	struct xfrmnl_ae*    ae;
619 	int err;
620 
621 	if ((err = xfrmnl_ae_parse(n, &ae)) < 0)
622 		return err;
623 
624 	err = pp->pp_cb((struct nl_object *) ae, pp);
625 
626 	xfrmnl_ae_put(ae);
627 	return err;
628 }
629 
630 /**
631  * @name XFRM AE Get
632  * @{
633  */
634 
xfrmnl_ae_build_get_request(struct nl_addr * daddr,unsigned int spi,unsigned int protocol,unsigned int mark_mask,unsigned int mark_value,struct nl_msg ** result)635 int xfrmnl_ae_build_get_request(struct nl_addr* daddr, unsigned int spi, unsigned int protocol,
636                                 unsigned int mark_mask, unsigned int mark_value, struct nl_msg **result)
637 {
638 	struct nl_msg *msg;
639 	struct xfrm_aevent_id   ae_id;
640 	struct xfrmnl_mark   mark;
641 
642 	if (!daddr || !spi)
643 	{
644 		fprintf(stderr, "APPLICATION BUG: %s:%d:%s: A valid destination address, spi must be specified\n",
645 				__FILE__, __LINE__, __func__);
646 		assert(0);
647 		return -NLE_MISSING_ATTR;
648 	}
649 
650 	memset(&ae_id, 0, sizeof(ae_id));
651 	memcpy (&ae_id.sa_id.daddr, nl_addr_get_binary_addr (daddr), sizeof (uint8_t) * nl_addr_get_len (daddr));
652 	ae_id.sa_id.spi    = htonl(spi);
653 	ae_id.sa_id.family = nl_addr_get_family (daddr);
654 	ae_id.sa_id.proto  = protocol;
655 
656 	if (!(msg = nlmsg_alloc_simple(XFRM_MSG_GETAE, 0)))
657 		return -NLE_NOMEM;
658 
659 	if (nlmsg_append(msg, &ae_id, sizeof(ae_id), NLMSG_ALIGNTO) < 0)
660 		goto nla_put_failure;
661 
662 	mark.m  =   mark_mask;
663 	mark.v  =   mark_value;
664 	NLA_PUT (msg, XFRMA_MARK, sizeof (struct xfrmnl_mark), &mark);
665 
666 	*result = msg;
667 	return 0;
668 
669 nla_put_failure:
670 	nlmsg_free(msg);
671 	return -NLE_MSGSIZE;
672 }
673 
xfrmnl_ae_get_kernel(struct nl_sock * sock,struct nl_addr * daddr,unsigned int spi,unsigned int protocol,unsigned int mark_mask,unsigned int mark_value,struct xfrmnl_ae ** result)674 int xfrmnl_ae_get_kernel(struct nl_sock* sock, struct nl_addr* daddr, unsigned int spi, unsigned int protocol,
675                          unsigned int mark_mask, unsigned int mark_value, struct xfrmnl_ae** result)
676 {
677 	struct nl_msg *msg = NULL;
678 	struct nl_object *obj;
679 	int err;
680 
681 	if ((err = xfrmnl_ae_build_get_request(daddr, spi, protocol, mark_mask, mark_value, &msg)) < 0)
682 		return err;
683 
684 	err = nl_send_auto(sock, msg);
685 	nlmsg_free(msg);
686 	if (err < 0)
687 		return err;
688 
689 	if ((err = nl_pickup(sock, &xfrm_ae_msg_parser, &obj)) < 0)
690 		return err;
691 
692 	/* We have used xfrm_ae_msg_parser(), object is definitely a xfrm ae */
693 	*result = (struct xfrmnl_ae *) obj;
694 
695 	/* If an object has been returned, we also need to wait for the ACK */
696 	if (err == 0 && obj)
697 		nl_wait_for_ack(sock);
698 
699 	return 0;
700 }
701 
702 /** @} */
703 
704 /**
705  * @name Attributes
706  * @{
707  */
708 
__assign_addr(struct xfrmnl_ae * ae,struct nl_addr ** pos,struct nl_addr * new,int flag,int nocheck)709 static inline int __assign_addr(struct xfrmnl_ae* ae, struct nl_addr **pos,
710 					struct nl_addr *new, int flag, int nocheck)
711 {
712 	if (!nocheck) {
713 		if (ae->ce_mask & XFRM_AE_ATTR_FAMILY) {
714 			if (nl_addr_get_family (new) != ae->sa_id.family)
715 				return -NLE_AF_MISMATCH;
716 		} else {
717 			ae->sa_id.family = nl_addr_get_family (new);
718 			ae->ce_mask |= XFRM_AE_ATTR_FAMILY;
719 		}
720 	}
721 
722 	if (*pos)
723 		nl_addr_put(*pos);
724 
725 	nl_addr_get(new);
726 	*pos = new;
727 
728 	ae->ce_mask |= flag;
729 
730 	return 0;
731 }
732 
733 
xfrmnl_ae_get_daddr(struct xfrmnl_ae * ae)734 struct nl_addr* xfrmnl_ae_get_daddr (struct xfrmnl_ae* ae)
735 {
736 	if (ae->ce_mask & XFRM_AE_ATTR_DADDR)
737 		return ae->sa_id.daddr;
738 	else
739 		return NULL;
740 }
741 
xfrmnl_ae_set_daddr(struct xfrmnl_ae * ae,struct nl_addr * addr)742 int xfrmnl_ae_set_daddr (struct xfrmnl_ae* ae, struct nl_addr* addr)
743 {
744 	return __assign_addr(ae, &ae->sa_id.daddr, addr, XFRM_AE_ATTR_DADDR, 0);
745 }
746 
xfrmnl_ae_get_spi(struct xfrmnl_ae * ae)747 int xfrmnl_ae_get_spi (struct xfrmnl_ae* ae)
748 {
749 	if (ae->ce_mask & XFRM_AE_ATTR_SPI)
750 		return ae->sa_id.spi;
751 	else
752 		return -1;
753 }
754 
xfrmnl_ae_set_spi(struct xfrmnl_ae * ae,unsigned int spi)755 int xfrmnl_ae_set_spi (struct xfrmnl_ae* ae, unsigned int spi)
756 {
757 	ae->sa_id.spi = spi;
758 	ae->ce_mask |= XFRM_AE_ATTR_SPI;
759 
760 	return 0;
761 }
762 
xfrmnl_ae_get_family(struct xfrmnl_ae * ae)763 int xfrmnl_ae_get_family (struct xfrmnl_ae* ae)
764 {
765 	if (ae->ce_mask & XFRM_AE_ATTR_FAMILY)
766 		return ae->sa_id.family;
767 	else
768 		return -1;
769 }
770 
xfrmnl_ae_set_family(struct xfrmnl_ae * ae,unsigned int family)771 int xfrmnl_ae_set_family (struct xfrmnl_ae* ae, unsigned int family)
772 {
773 	ae->sa_id.family = family;
774 	ae->ce_mask |= XFRM_AE_ATTR_FAMILY;
775 
776 	return 0;
777 }
778 
xfrmnl_ae_get_proto(struct xfrmnl_ae * ae)779 int xfrmnl_ae_get_proto (struct xfrmnl_ae* ae)
780 {
781 	if (ae->ce_mask & XFRM_AE_ATTR_PROTO)
782 		return ae->sa_id.proto;
783 	else
784 		return -1;
785 }
786 
xfrmnl_ae_set_proto(struct xfrmnl_ae * ae,unsigned int protocol)787 int xfrmnl_ae_set_proto (struct xfrmnl_ae* ae, unsigned int protocol)
788 {
789 	ae->sa_id.proto = protocol;
790 	ae->ce_mask |= XFRM_AE_ATTR_PROTO;
791 
792 	return 0;
793 }
794 
xfrmnl_ae_get_saddr(struct xfrmnl_ae * ae)795 struct nl_addr* xfrmnl_ae_get_saddr (struct xfrmnl_ae* ae)
796 {
797 	if (ae->ce_mask & XFRM_AE_ATTR_SADDR)
798 		return ae->saddr;
799 	else
800 		return NULL;
801 }
802 
xfrmnl_ae_set_saddr(struct xfrmnl_ae * ae,struct nl_addr * addr)803 int xfrmnl_ae_set_saddr (struct xfrmnl_ae* ae, struct nl_addr* addr)
804 {
805 	return 	__assign_addr(ae, &ae->saddr, addr, XFRM_AE_ATTR_SADDR, 1);
806 }
807 
xfrmnl_ae_get_flags(struct xfrmnl_ae * ae)808 int xfrmnl_ae_get_flags (struct xfrmnl_ae* ae)
809 {
810 	if (ae->ce_mask & XFRM_AE_ATTR_FLAGS)
811 		return ae->flags;
812 	else
813 		return -1;
814 }
815 
xfrmnl_ae_set_flags(struct xfrmnl_ae * ae,unsigned int flags)816 int xfrmnl_ae_set_flags (struct xfrmnl_ae* ae, unsigned int flags)
817 {
818 	ae->flags = flags;
819 	ae->ce_mask |= XFRM_AE_ATTR_FLAGS;
820 
821 	return 0;
822 }
823 
xfrmnl_ae_get_reqid(struct xfrmnl_ae * ae)824 int xfrmnl_ae_get_reqid (struct xfrmnl_ae* ae)
825 {
826 	if (ae->ce_mask & XFRM_AE_ATTR_REQID)
827 		return ae->reqid;
828 	else
829 		return -1;
830 }
831 
xfrmnl_ae_set_reqid(struct xfrmnl_ae * ae,unsigned int reqid)832 int xfrmnl_ae_set_reqid (struct xfrmnl_ae* ae, unsigned int reqid)
833 {
834 	ae->reqid = reqid;
835 	ae->ce_mask |= XFRM_AE_ATTR_REQID;
836 
837 	return 0;
838 }
839 
xfrmnl_ae_get_mark(struct xfrmnl_ae * ae,unsigned int * mark_mask,unsigned int * mark_value)840 int xfrmnl_ae_get_mark (struct xfrmnl_ae* ae, unsigned int* mark_mask, unsigned int* mark_value)
841 {
842 	if (mark_mask == NULL || mark_value == NULL)
843 		return -1;
844 
845 	if (ae->ce_mask & XFRM_AE_ATTR_MARK)
846 	{
847 		*mark_mask  =   ae->mark.m;
848 		*mark_value  =   ae->mark.v;
849 
850 		return 0;
851 	}
852 	else
853 		return -1;
854 }
855 
xfrmnl_ae_set_mark(struct xfrmnl_ae * ae,unsigned int value,unsigned int mask)856 int xfrmnl_ae_set_mark (struct xfrmnl_ae* ae, unsigned int value, unsigned int mask)
857 {
858 	ae->mark.v  = value;
859 	ae->mark.m  = mask;
860 	ae->ce_mask |= XFRM_AE_ATTR_MARK;
861 
862 	return 0;
863 }
864 
xfrmnl_ae_get_curlifetime(struct xfrmnl_ae * ae,unsigned long long int * curr_bytes,unsigned long long int * curr_packets,unsigned long long int * curr_add_time,unsigned long long int * curr_use_time)865 int xfrmnl_ae_get_curlifetime (struct xfrmnl_ae* ae, unsigned long long int* curr_bytes,
866                                unsigned long long int* curr_packets, unsigned long long int* curr_add_time,
867                                unsigned long long int* curr_use_time)
868 {
869 	if (curr_bytes == NULL || curr_packets == NULL || curr_add_time == NULL || curr_use_time == NULL)
870 		return -1;
871 
872 	if (ae->ce_mask & XFRM_AE_ATTR_LIFETIME)
873 	{
874 		*curr_bytes     =   ae->lifetime_cur.bytes;
875 		*curr_packets   =   ae->lifetime_cur.packets;
876 		*curr_add_time  =   ae->lifetime_cur.add_time;
877 		*curr_use_time  =   ae->lifetime_cur.use_time;
878 
879 		return 0;
880 	}
881 	else
882 		return -1;
883 }
884 
xfrmnl_ae_set_curlifetime(struct xfrmnl_ae * ae,unsigned long long int curr_bytes,unsigned long long int curr_packets,unsigned long long int curr_add_time,unsigned long long int curr_use_time)885 int xfrmnl_ae_set_curlifetime (struct xfrmnl_ae* ae, unsigned long long int curr_bytes,
886                                unsigned long long int curr_packets, unsigned long long int curr_add_time,
887                                unsigned long long int curr_use_time)
888 {
889 	ae->lifetime_cur.bytes = curr_bytes;
890 	ae->lifetime_cur.packets = curr_packets;
891 	ae->lifetime_cur.add_time = curr_add_time;
892 	ae->lifetime_cur.use_time = curr_use_time;
893 	ae->ce_mask |= XFRM_AE_ATTR_LIFETIME;
894 
895 	return 0;
896 }
897 
xfrmnl_ae_get_replay_maxage(struct xfrmnl_ae * ae)898 int xfrmnl_ae_get_replay_maxage (struct xfrmnl_ae* ae)
899 {
900 	if (ae->ce_mask & XFRM_AE_ATTR_REPLAY_MAXAGE)
901 		return ae->replay_maxage;
902 	else
903 		return -1;
904 }
905 
xfrmnl_ae_set_replay_maxage(struct xfrmnl_ae * ae,unsigned int replay_maxage)906 int xfrmnl_ae_set_replay_maxage (struct xfrmnl_ae* ae, unsigned int replay_maxage)
907 {
908 	ae->replay_maxage  = replay_maxage;
909 	ae->ce_mask |= XFRM_AE_ATTR_REPLAY_MAXAGE;
910 
911 	return 0;
912 }
913 
xfrmnl_ae_get_replay_maxdiff(struct xfrmnl_ae * ae)914 int xfrmnl_ae_get_replay_maxdiff (struct xfrmnl_ae* ae)
915 {
916 	if (ae->ce_mask & XFRM_AE_ATTR_REPLAY_MAXDIFF)
917 		return ae->replay_maxdiff;
918 	else
919 		return -1;
920 }
921 
xfrmnl_ae_set_replay_maxdiff(struct xfrmnl_ae * ae,unsigned int replay_maxdiff)922 int xfrmnl_ae_set_replay_maxdiff (struct xfrmnl_ae* ae, unsigned int replay_maxdiff)
923 {
924 	ae->replay_maxdiff  = replay_maxdiff;
925 	ae->ce_mask |= XFRM_AE_ATTR_REPLAY_MAXDIFF;
926 
927 	return 0;
928 }
929 
xfrmnl_ae_get_replay_state(struct xfrmnl_ae * ae,unsigned int * oseq,unsigned int * seq,unsigned int * bmp)930 int xfrmnl_ae_get_replay_state (struct xfrmnl_ae* ae, unsigned int* oseq, unsigned int* seq, unsigned int* bmp)
931 {
932 	if (ae->ce_mask & XFRM_AE_ATTR_REPLAY_STATE)
933 	{
934 		if (ae->replay_state_esn == NULL)
935 		{
936 			*oseq   =   ae->replay_state.oseq;
937 			*seq    =   ae->replay_state.seq;
938 			*bmp    =   ae->replay_state.bitmap;
939 
940 			return 0;
941 		}
942 		else
943 		{
944 			return -1;
945 		}
946 	}
947 	else
948 		return -1;
949 }
950 
xfrmnl_ae_set_replay_state(struct xfrmnl_ae * ae,unsigned int oseq,unsigned int seq,unsigned int bitmap)951 int xfrmnl_ae_set_replay_state (struct xfrmnl_ae* ae, unsigned int oseq, unsigned int seq, unsigned int bitmap)
952 {
953 	ae->replay_state.oseq = oseq;
954 	ae->replay_state.seq = seq;
955 	ae->replay_state.bitmap = bitmap;
956 	ae->ce_mask |= XFRM_AE_ATTR_REPLAY_STATE;
957 
958 	return 0;
959 }
960 
xfrmnl_ae_get_replay_state_esn(struct xfrmnl_ae * ae,unsigned int * oseq,unsigned int * seq,unsigned int * oseq_hi,unsigned int * seq_hi,unsigned int * replay_window,unsigned int * bmp_len,unsigned int * bmp)961 int xfrmnl_ae_get_replay_state_esn(struct xfrmnl_ae* ae, unsigned int* oseq, unsigned int* seq, unsigned int* oseq_hi,
962                                    unsigned int* seq_hi, unsigned int* replay_window, unsigned int* bmp_len, unsigned int* bmp)
963 {
964 	if (ae->ce_mask & XFRM_AE_ATTR_REPLAY_STATE)
965 	{
966 		if (ae->replay_state_esn)
967 		{
968 			*oseq   =   ae->replay_state_esn->oseq;
969 			*seq    =   ae->replay_state_esn->seq;
970 			*oseq_hi=   ae->replay_state_esn->oseq_hi;
971 			*seq_hi =   ae->replay_state_esn->seq_hi;
972 			*replay_window  =   ae->replay_state_esn->replay_window;
973 			*bmp_len        =   ae->replay_state_esn->bmp_len; // In number of 32 bit words
974 			memcpy (bmp, ae->replay_state_esn->bmp, ae->replay_state_esn->bmp_len * sizeof (uint32_t));
975 
976 			return 0;
977 		}
978 		else
979 		{
980 			return -1;
981 		}
982 	}
983 	else
984 		return -1;
985 }
986 
xfrmnl_ae_set_replay_state_esn(struct xfrmnl_ae * ae,unsigned int oseq,unsigned int seq,unsigned int oseq_hi,unsigned int seq_hi,unsigned int replay_window,unsigned int bmp_len,unsigned int * bmp)987 int xfrmnl_ae_set_replay_state_esn(struct xfrmnl_ae* ae, unsigned int oseq, unsigned int seq,
988                                    unsigned int oseq_hi, unsigned int seq_hi, unsigned int replay_window,
989                                    unsigned int bmp_len, unsigned int* bmp)
990 {
991 	/* Free the old replay ESN state and allocate new one */
992 	if (ae->replay_state_esn)
993 		free (ae->replay_state_esn);
994 
995 	if ((ae->replay_state_esn = calloc (1, sizeof (struct xfrmnl_replay_state_esn) + sizeof (uint32_t) * bmp_len)) == NULL)
996 		return -1;
997 
998 	ae->replay_state_esn->oseq = oseq;
999 	ae->replay_state_esn->seq = seq;
1000 	ae->replay_state_esn->oseq_hi = oseq_hi;
1001 	ae->replay_state_esn->seq_hi = seq_hi;
1002 	ae->replay_state_esn->replay_window = replay_window;
1003 	ae->replay_state_esn->bmp_len = bmp_len; // In number of 32 bit words
1004 	memcpy (ae->replay_state_esn->bmp, bmp, bmp_len * sizeof (uint32_t));
1005 	ae->ce_mask |= XFRM_AE_ATTR_REPLAY_STATE;
1006 
1007 	return 0;
1008 }
1009 
1010 /** @} */
1011 
1012 static struct nl_object_ops xfrm_ae_obj_ops = {
1013 	.oo_name        =   "xfrm/ae",
1014 	.oo_size        =   sizeof(struct xfrmnl_ae),
1015 	.oo_free_data   =   xfrm_ae_free_data,
1016 	.oo_clone       =   xfrm_ae_clone,
1017 	.oo_dump        =   {
1018 	                        [NL_DUMP_LINE]      =   xfrm_ae_dump_line,
1019 	                        [NL_DUMP_DETAILS]   =   xfrm_ae_dump_details,
1020 	                        [NL_DUMP_STATS]     =   xfrm_ae_dump_stats,
1021 	                    },
1022 	.oo_compare     =   xfrm_ae_compare,
1023 	.oo_attrs2str   =   xfrm_ae_attrs2str,
1024 	.oo_id_attrs    =   (XFRM_AE_ATTR_DADDR | XFRM_AE_ATTR_SPI | XFRM_AE_ATTR_PROTO),
1025 };
1026 
1027 /** @} */
1028 
1029