• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <netlink-private/netlink.h>
124 #include <netlink/netlink.h>
125 #include <netlink/cache.h>
126 #include <netlink/object.h>
127 #include <netlink/xfrm/ae.h>
128 #include <linux/xfrm.h>
129 
130 /** @cond SKIP */
131 #define XFRM_AE_ATTR_DADDR          0x01
132 #define XFRM_AE_ATTR_SPI            0x02
133 #define XFRM_AE_ATTR_PROTO          0x04
134 #define XFRM_AE_ATTR_SADDR          0x08
135 #define XFRM_AE_ATTR_FLAGS          0x10
136 #define XFRM_AE_ATTR_REQID          0x20
137 #define XFRM_AE_ATTR_MARK           0x40
138 #define XFRM_AE_ATTR_LIFETIME       0x80
139 #define XFRM_AE_ATTR_REPLAY_MAXAGE  0x100
140 #define XFRM_AE_ATTR_REPLAY_MAXDIFF 0x200
141 #define XFRM_AE_ATTR_REPLAY_STATE   0x400
142 #define XFRM_AE_ATTR_FAMILY         0x800
143 
144 static struct nl_object_ops xfrm_ae_obj_ops;
145 /** @endcond */
146 
147 
xfrm_ae_free_data(struct nl_object * c)148 static void xfrm_ae_free_data(struct nl_object *c)
149 {
150 	struct xfrmnl_ae* ae =   nl_object_priv (c);
151 
152 	if (ae == NULL)
153 		return;
154 
155 	nl_addr_put (ae->sa_id.daddr);
156 	nl_addr_put (ae->saddr);
157 
158 	if (ae->replay_state_esn)
159 		free (ae->replay_state_esn);
160 }
161 
xfrm_ae_clone(struct nl_object * _dst,struct nl_object * _src)162 static int xfrm_ae_clone(struct nl_object *_dst, struct nl_object *_src)
163 {
164 	struct xfrmnl_ae* dst = nl_object_priv(_dst);
165 	struct xfrmnl_ae* src = nl_object_priv(_src);
166 
167 	dst->sa_id.daddr = NULL;
168 	dst->saddr = NULL;
169 	dst->replay_state_esn = NULL;
170 
171 	if (src->sa_id.daddr) {
172 		if ((dst->sa_id.daddr = nl_addr_clone (src->sa_id.daddr)) == NULL)
173 			return -NLE_NOMEM;
174 	}
175 
176 	if (src->saddr) {
177 		if ((dst->saddr = nl_addr_clone (src->saddr)) == NULL)
178 			return -NLE_NOMEM;
179 	}
180 
181 	if (src->replay_state_esn) {
182 		uint32_t len = sizeof (struct xfrmnl_replay_state_esn) + (sizeof (uint32_t) * src->replay_state_esn->bmp_len);
183 
184 		if ((dst->replay_state_esn = malloc (len)) == NULL)
185 			return -NLE_NOMEM;
186 		memcpy (dst->replay_state_esn, src->replay_state_esn, len);
187 	}
188 
189 	return 0;
190 }
191 
xfrm_ae_compare(struct nl_object * _a,struct nl_object * _b,uint64_t attrs,int flags)192 static uint64_t xfrm_ae_compare(struct nl_object *_a, struct nl_object *_b,
193 				uint64_t attrs, int flags)
194 {
195 	struct xfrmnl_ae* a  =   (struct xfrmnl_ae *) _a;
196 	struct xfrmnl_ae* b  =   (struct xfrmnl_ae *) _b;
197 	uint64_t diff = 0;
198 	int found = 0;
199 
200 #define XFRM_AE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, XFRM_AE_ATTR_##ATTR, a, b, EXPR)
201 	diff |= XFRM_AE_DIFF(DADDR,	nl_addr_cmp(a->sa_id.daddr, b->sa_id.daddr));
202 	diff |= XFRM_AE_DIFF(SPI,	a->sa_id.spi != b->sa_id.spi);
203 	diff |= XFRM_AE_DIFF(PROTO,	a->sa_id.proto != b->sa_id.proto);
204 	diff |= XFRM_AE_DIFF(SADDR,	nl_addr_cmp(a->saddr, b->saddr));
205 	diff |= XFRM_AE_DIFF(FLAGS, a->flags != b->flags);
206 	diff |= XFRM_AE_DIFF(REQID, a->reqid != b->reqid);
207 	diff |= XFRM_AE_DIFF(MARK, (a->mark.v & a->mark.m) != (b->mark.v & b->mark.m));
208 	diff |= XFRM_AE_DIFF(REPLAY_MAXAGE, a->replay_maxage != b->replay_maxage);
209 	diff |= XFRM_AE_DIFF(REPLAY_MAXDIFF, a->replay_maxdiff != b->replay_maxdiff);
210 
211 	/* Compare replay states */
212 	found = AVAILABLE_MISMATCH (a, b, XFRM_AE_ATTR_REPLAY_STATE);
213 	if (found == 0) // attribute exists in both objects
214 	{
215 		if (((a->replay_state_esn != NULL) && (b->replay_state_esn == NULL)) ||
216 			((a->replay_state_esn == NULL) && (b->replay_state_esn != NULL)))
217 			found |= 1;
218 
219 		if (found == 0) // same replay type. compare actual values
220 		{
221 			if (a->replay_state_esn)
222 			{
223 				if (a->replay_state_esn->bmp_len != b->replay_state_esn->bmp_len)
224 					diff |= 1;
225 				else
226 				{
227 					uint32_t len = sizeof (struct xfrmnl_replay_state_esn) + (sizeof (uint32_t) * a->replay_state_esn->bmp_len);
228 					diff |= memcmp (a->replay_state_esn, b->replay_state_esn, len);
229 				}
230 			}
231 			else
232 			{
233 				if ((a->replay_state.oseq != b->replay_state.oseq) ||
234 				    (a->replay_state.seq != b->replay_state.seq) ||
235 				    (a->replay_state.bitmap != b->replay_state.bitmap))
236 					diff |= 1;
237 			}
238 		}
239 	}
240 #undef XFRM_AE_DIFF
241 
242 	return diff;
243 }
244 
245 /**
246  * @name XFRM AE Attribute Translations
247  * @{
248  */
249 static const struct trans_tbl ae_attrs[] =
250 {
251 	__ADD(XFRM_AE_ATTR_DADDR, daddr),
252 	__ADD(XFRM_AE_ATTR_SPI, spi),
253 	__ADD(XFRM_AE_ATTR_PROTO, protocol),
254 	__ADD(XFRM_AE_ATTR_SADDR, saddr),
255 	__ADD(XFRM_AE_ATTR_FLAGS, flags),
256 	__ADD(XFRM_AE_ATTR_REQID, reqid),
257 	__ADD(XFRM_AE_ATTR_MARK, mark),
258 	__ADD(XFRM_AE_ATTR_LIFETIME, cur_lifetime),
259 	__ADD(XFRM_AE_ATTR_REPLAY_MAXAGE, replay_maxage),
260 	__ADD(XFRM_AE_ATTR_REPLAY_MAXDIFF, replay_maxdiff),
261 	__ADD(XFRM_AE_ATTR_REPLAY_STATE, replay_state),
262 };
263 
xfrm_ae_attrs2str(int attrs,char * buf,size_t len)264 static char* xfrm_ae_attrs2str (int attrs, char *buf, size_t len)
265 {
266 	return __flags2str(attrs, buf, len, ae_attrs, ARRAY_SIZE(ae_attrs));
267 }
268 /** @} */
269 
270 /**
271  * @name XFRM AE Flags Translations
272  * @{
273  */
274 
275 static const struct trans_tbl ae_flags[] = {
276 	__ADD(XFRM_AE_UNSPEC, unspecified),
277 	__ADD(XFRM_AE_RTHR, replay threshold),
278 	__ADD(XFRM_AE_RVAL, replay value),
279 	__ADD(XFRM_AE_LVAL, lifetime value),
280 	__ADD(XFRM_AE_ETHR, expiry time threshold),
281 	__ADD(XFRM_AE_CR, replay update event),
282 	__ADD(XFRM_AE_CE, timer expiry event),
283 	__ADD(XFRM_AE_CU, policy update event),
284 };
285 
xfrmnl_ae_flags2str(int flags,char * buf,size_t len)286 char* xfrmnl_ae_flags2str(int flags, char *buf, size_t len)
287 {
288 	return __flags2str (flags, buf, len, ae_flags, ARRAY_SIZE(ae_flags));
289 }
290 
xfrmnl_ae_str2flag(const char * name)291 int xfrmnl_ae_str2flag(const char *name)
292 {
293 	return __str2flags(name, ae_flags, ARRAY_SIZE(ae_flags));
294 }
295 /** @} */
296 
xfrm_ae_dump_line(struct nl_object * a,struct nl_dump_params * p)297 static void xfrm_ae_dump_line(struct nl_object *a, struct nl_dump_params *p)
298 {
299 	char                dst[INET6_ADDRSTRLEN+5], src[INET6_ADDRSTRLEN+5];
300 	struct xfrmnl_ae*   ae  =   (struct xfrmnl_ae *) a;
301 	char                flags[128], buf[128];
302 	time_t              add_time, use_time;
303 	struct tm           *add_time_tm, *use_time_tm;
304 
305 	nl_dump_line(p, "src %s dst %s \n", nl_addr2str(ae->saddr, src, sizeof(src)),
306 				nl_addr2str(ae->sa_id.daddr, dst, sizeof(dst)));
307 
308 	nl_dump_line(p, "\tproto %s spi 0x%x reqid %u ",
309 				nl_ip_proto2str (ae->sa_id.proto, buf, sizeof (buf)),
310 				ae->sa_id.spi, ae->reqid);
311 
312 	xfrmnl_ae_flags2str(ae->flags, flags, sizeof (flags));
313 	nl_dump_line(p, "flags %s(0x%x) mark mask/value 0x%x/0x%x \n", flags,
314 				ae->flags, ae->mark.m, ae->mark.v);
315 
316 	nl_dump_line(p, "\tlifetime current: \n");
317 	nl_dump_line(p, "\t\tbytes %llu packets %llu \n",
318 		     (long long unsigned)ae->lifetime_cur.bytes,
319 		     (long long unsigned)ae->lifetime_cur.packets);
320 	if (ae->lifetime_cur.add_time != 0)
321 	{
322 		add_time = ae->lifetime_cur.add_time;
323 		add_time_tm = gmtime (&add_time);
324 		strftime (flags, 128, "%Y-%m-%d %H-%M-%S", add_time_tm);
325 	}
326 	else
327 	{
328 		sprintf (flags, "%s", "-");
329 	}
330 
331 	if (ae->lifetime_cur.use_time != 0)
332 	{
333 		use_time = ae->lifetime_cur.use_time;
334 		use_time_tm = gmtime (&use_time);
335 		strftime (buf, 128, "%Y-%m-%d %H-%M-%S", use_time_tm);
336 	}
337 	else
338 	{
339 		sprintf (buf, "%s", "-");
340 	}
341 	nl_dump_line(p, "\t\tadd_time: %s, use_time: %s\n", flags, buf);
342 
343 	nl_dump_line(p, "\treplay info: \n");
344 	nl_dump_line(p, "\t\tmax age %u max diff %u \n", ae->replay_maxage, ae->replay_maxdiff);
345 
346 	nl_dump_line(p, "\treplay state info: \n");
347 	if (ae->replay_state_esn)
348 	{
349 		nl_dump_line(p, "\t\toseq %u seq %u oseq_hi %u seq_hi %u replay window: %u \n",
350 					ae->replay_state_esn->oseq, ae->replay_state_esn->seq,
351 					ae->replay_state_esn->oseq_hi, ae->replay_state_esn->seq_hi,
352 					ae->replay_state_esn->replay_window);
353 	}
354 	else
355 	{
356 		nl_dump_line(p, "\t\toseq %u seq %u bitmap: %u \n", ae->replay_state.oseq,
357 					ae->replay_state.seq, ae->replay_state.bitmap);
358 	}
359 
360 	nl_dump(p, "\n");
361 }
362 
xfrm_ae_dump_details(struct nl_object * a,struct nl_dump_params * p)363 static void xfrm_ae_dump_details(struct nl_object *a, struct nl_dump_params *p)
364 {
365 	xfrm_ae_dump_line(a, p);
366 }
367 
xfrm_ae_dump_stats(struct nl_object * a,struct nl_dump_params * p)368 static void xfrm_ae_dump_stats(struct nl_object *a, struct nl_dump_params *p)
369 {
370 	xfrm_ae_dump_details(a, p);
371 }
372 
373 
build_xfrm_ae_message(struct xfrmnl_ae * tmpl,int cmd,int flags,struct nl_msg ** result)374 static int build_xfrm_ae_message(struct xfrmnl_ae *tmpl, int cmd, int flags,
375 			   struct nl_msg **result)
376 {
377 	struct nl_msg*          msg;
378 	struct xfrm_aevent_id   ae_id;
379 
380 	if (!(tmpl->ce_mask & XFRM_AE_ATTR_DADDR) ||
381 		!(tmpl->ce_mask & XFRM_AE_ATTR_SPI) ||
382 		!(tmpl->ce_mask & XFRM_AE_ATTR_PROTO))
383 		return -NLE_MISSING_ATTR;
384 
385 	memset(&ae_id, 0, sizeof(ae_id));
386 
387 	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));
388 	ae_id.sa_id.spi    = htonl(tmpl->sa_id.spi);
389 	ae_id.sa_id.family = tmpl->sa_id.family;
390 	ae_id.sa_id.proto  = tmpl->sa_id.proto;
391 
392 	if (tmpl->ce_mask & XFRM_AE_ATTR_SADDR)
393 		memcpy (&ae_id.saddr, nl_addr_get_binary_addr (tmpl->saddr), sizeof (uint8_t) * nl_addr_get_len (tmpl->saddr));
394 
395 	if (tmpl->ce_mask & XFRM_AE_ATTR_FLAGS)
396 		ae_id.flags    = tmpl->flags;
397 
398 	if (tmpl->ce_mask & XFRM_AE_ATTR_REQID)
399 		ae_id.reqid    = tmpl->reqid;
400 
401 	msg = nlmsg_alloc_simple(cmd, flags);
402 	if (!msg)
403 		return -NLE_NOMEM;
404 
405 	if (nlmsg_append(msg, &ae_id, sizeof(ae_id), NLMSG_ALIGNTO) < 0)
406 		goto nla_put_failure;
407 
408 	if (tmpl->ce_mask & XFRM_AE_ATTR_MARK)
409 		NLA_PUT (msg, XFRMA_MARK, sizeof (struct xfrmnl_mark), &tmpl->mark);
410 
411 	if (tmpl->ce_mask & XFRM_AE_ATTR_LIFETIME)
412 		NLA_PUT (msg, XFRMA_LTIME_VAL, sizeof (struct xfrmnl_lifetime_cur), &tmpl->lifetime_cur);
413 
414 	if (tmpl->ce_mask & XFRM_AE_ATTR_REPLAY_MAXAGE)
415 		NLA_PUT_U32 (msg, XFRMA_ETIMER_THRESH, tmpl->replay_maxage);
416 
417 	if (tmpl->ce_mask & XFRM_AE_ATTR_REPLAY_MAXDIFF)
418 		NLA_PUT_U32 (msg, XFRMA_REPLAY_THRESH, tmpl->replay_maxdiff);
419 
420 	if (tmpl->ce_mask & XFRM_AE_ATTR_REPLAY_STATE) {
421 		if (tmpl->replay_state_esn) {
422 			uint32_t len = sizeof (struct xfrm_replay_state_esn) + (sizeof (uint32_t) * tmpl->replay_state_esn->bmp_len);
423 			NLA_PUT (msg, XFRMA_REPLAY_ESN_VAL, len, tmpl->replay_state_esn);
424 		}
425 		else {
426 			NLA_PUT (msg, XFRMA_REPLAY_VAL, sizeof (struct xfrmnl_replay_state), &tmpl->replay_state);
427 		}
428 	}
429 
430 	*result = msg;
431 	return 0;
432 
433 nla_put_failure:
434 	nlmsg_free(msg);
435 	return -NLE_MSGSIZE;
436 }
437 
438 /**
439  * @name XFRM AE Update
440  * @{
441  */
442 
xfrmnl_ae_set(struct nl_sock * sk,struct xfrmnl_ae * ae,int flags)443 int xfrmnl_ae_set(struct nl_sock* sk, struct xfrmnl_ae* ae, int flags)
444 {
445 	int err;
446 	struct nl_msg *msg;
447 
448 	if ((err = build_xfrm_ae_message(ae, XFRM_MSG_NEWAE, flags|NLM_F_REPLACE, &msg)) < 0)
449 		return err;
450 
451 	err = nl_send_auto_complete(sk, msg);
452 	nlmsg_free(msg);
453 	if (err < 0)
454 		return err;
455 
456 	return nl_wait_for_ack(sk);
457 }
458 
459 /** @} */
460 
461 /**
462  * @name XFRM AE Object Allocation/Freeage
463  * @{
464  */
465 
xfrmnl_ae_alloc(void)466 struct xfrmnl_ae* xfrmnl_ae_alloc(void)
467 {
468 	return (struct xfrmnl_ae*) nl_object_alloc(&xfrm_ae_obj_ops);
469 }
470 
xfrmnl_ae_put(struct xfrmnl_ae * ae)471 void xfrmnl_ae_put(struct xfrmnl_ae* ae)
472 {
473 	nl_object_put((struct nl_object *) ae);
474 }
475 
476 /** @} */
477 
478 static struct nla_policy xfrm_ae_policy[XFRMA_MAX+1] = {
479 	[XFRMA_LTIME_VAL]       = { .minlen = sizeof(struct xfrm_lifetime_cur) },
480 	[XFRMA_REPLAY_VAL]      = { .minlen = sizeof(struct xfrm_replay_state) },
481 	[XFRMA_REPLAY_THRESH]   = { .type = NLA_U32 },
482 	[XFRMA_ETIMER_THRESH]   = { .type = NLA_U32 },
483 	[XFRMA_SRCADDR]         = { .minlen = sizeof(xfrm_address_t) },
484 	[XFRMA_MARK]            = { .minlen = sizeof(struct xfrm_mark) },
485 	[XFRMA_REPLAY_ESN_VAL]  = { .minlen = sizeof(struct xfrm_replay_state_esn) },
486 };
487 
xfrmnl_ae_parse(struct nlmsghdr * n,struct xfrmnl_ae ** result)488 int xfrmnl_ae_parse(struct nlmsghdr *n, struct xfrmnl_ae **result)
489 {
490 	struct xfrmnl_ae*    ae;
491 	struct nlattr           *tb[XFRMA_MAX + 1];
492 	struct xfrm_aevent_id*  ae_id;
493 	int err;
494 
495 	ae = xfrmnl_ae_alloc();
496 	if (!ae) {
497 		err = -NLE_NOMEM;
498 		goto errout;
499 	}
500 
501 	ae->ce_msgtype = n->nlmsg_type;
502 	ae_id = nlmsg_data(n);
503 
504 	err = nlmsg_parse(n, sizeof(struct xfrm_aevent_id), tb, XFRMA_MAX, xfrm_ae_policy);
505 	if (err < 0)
506 		goto errout;
507 
508 	ae->sa_id.daddr = nl_addr_build(ae_id->sa_id.family, &ae_id->sa_id.daddr, sizeof (ae_id->sa_id.daddr));
509 	ae->sa_id.family= ae_id->sa_id.family;
510 	ae->sa_id.spi   = ntohl(ae_id->sa_id.spi);
511 	ae->sa_id.proto = ae_id->sa_id.proto;
512 	ae->saddr       = nl_addr_build(ae_id->sa_id.family, &ae_id->saddr, sizeof (ae_id->saddr));
513 	ae->reqid       = ae_id->reqid;
514 	ae->flags       = ae_id->flags;
515 	ae->ce_mask |= (XFRM_AE_ATTR_DADDR | XFRM_AE_ATTR_FAMILY | XFRM_AE_ATTR_SPI |
516 					XFRM_AE_ATTR_PROTO | XFRM_AE_ATTR_SADDR | XFRM_AE_ATTR_REQID |
517 					XFRM_AE_ATTR_FLAGS);
518 
519 	if (tb[XFRMA_MARK]) {
520 		struct xfrm_mark* m =   nla_data(tb[XFRMA_MARK]);
521 		ae->mark.m  =   m->m;
522 		ae->mark.v  =   m->v;
523 		ae->ce_mask |= XFRM_AE_ATTR_MARK;
524 	}
525 
526 	if (tb[XFRMA_LTIME_VAL]) {
527 		struct xfrm_lifetime_cur* cur =   nla_data(tb[XFRMA_LTIME_VAL]);
528 		ae->lifetime_cur.bytes      =   cur->bytes;
529 		ae->lifetime_cur.packets    =   cur->packets;
530 		ae->lifetime_cur.add_time   =   cur->add_time;
531 		ae->lifetime_cur.use_time   =   cur->use_time;
532 		ae->ce_mask |= XFRM_AE_ATTR_LIFETIME;
533 	}
534 
535 	if (tb[XFRM_AE_ETHR]) {
536 		ae->replay_maxage       =   *(uint32_t*)nla_data(tb[XFRM_AE_ETHR]);
537 		ae->ce_mask |= XFRM_AE_ATTR_REPLAY_MAXAGE;
538 	}
539 
540 	if (tb[XFRM_AE_RTHR]) {
541 		ae->replay_maxdiff      =   *(uint32_t*)nla_data(tb[XFRM_AE_RTHR]);
542 		ae->ce_mask |= XFRM_AE_ATTR_REPLAY_MAXDIFF;
543 	}
544 
545 	if (tb[XFRMA_REPLAY_ESN_VAL]) {
546 		struct xfrm_replay_state_esn* esn =  nla_data (tb[XFRMA_REPLAY_ESN_VAL]);
547 		uint32_t len = sizeof (struct xfrmnl_replay_state_esn) +  (sizeof (uint32_t) * esn->bmp_len);
548 
549 		if ((ae->replay_state_esn = calloc (1, len)) == NULL) {
550 			err = -ENOMEM;
551 			goto errout;
552 		}
553 		ae->replay_state_esn->oseq       =  esn->oseq;
554 		ae->replay_state_esn->seq        =  esn->seq;
555 		ae->replay_state_esn->oseq_hi    =  esn->oseq_hi;
556 		ae->replay_state_esn->seq_hi     =  esn->seq_hi;
557 		ae->replay_state_esn->replay_window   =   esn->replay_window;
558 		ae->replay_state_esn->bmp_len    =   esn->bmp_len;
559 		memcpy (ae->replay_state_esn->bmp, esn->bmp, sizeof (uint32_t) * esn->bmp_len);
560 		ae->ce_mask |= XFRM_AE_ATTR_REPLAY_STATE;
561 	}
562 	else
563 	{
564 		struct xfrm_replay_state* replay_state = nla_data (tb[XFRMA_REPLAY_VAL]);
565 		ae->replay_state.oseq       =   replay_state->oseq;
566 		ae->replay_state.seq        =   replay_state->seq;
567 		ae->replay_state.bitmap     =   replay_state->bitmap;
568 		ae->ce_mask |= XFRM_AE_ATTR_REPLAY_STATE;
569 
570 		ae->replay_state_esn = NULL;
571 	}
572 
573 	*result = ae;
574 	return 0;
575 
576 errout:
577 	xfrmnl_ae_put(ae);
578 	return err;
579 }
580 
xfrm_ae_msg_parser(struct nl_cache_ops * ops,struct sockaddr_nl * who,struct nlmsghdr * n,struct nl_parser_param * pp)581 static int xfrm_ae_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
582 				struct nlmsghdr *n, struct nl_parser_param *pp)
583 {
584 	struct xfrmnl_ae*    ae;
585 	int err;
586 
587 	if ((err = xfrmnl_ae_parse(n, &ae)) < 0)
588 		return err;
589 
590 	err = pp->pp_cb((struct nl_object *) ae, pp);
591 
592 	xfrmnl_ae_put(ae);
593 	return err;
594 }
595 
596 /**
597  * @name XFRM AE Get
598  * @{
599  */
600 
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)601 int xfrmnl_ae_build_get_request(struct nl_addr* daddr, unsigned int spi, unsigned int protocol,
602                                 unsigned int mark_mask, unsigned int mark_value, struct nl_msg **result)
603 {
604 	struct nl_msg *msg;
605 	struct xfrm_aevent_id   ae_id;
606 	struct xfrmnl_mark   mark;
607 
608 	if (!daddr || !spi)
609 	{
610 		fprintf(stderr, "APPLICATION BUG: %s:%d:%s: A valid destination address, spi must be specified\n",
611 				__FILE__, __LINE__, __func__);
612 		assert(0);
613 		return -NLE_MISSING_ATTR;
614 	}
615 
616 	memset(&ae_id, 0, sizeof(ae_id));
617 	memcpy (&ae_id.sa_id.daddr, nl_addr_get_binary_addr (daddr), sizeof (uint8_t) * nl_addr_get_len (daddr));
618 	ae_id.sa_id.spi    = htonl(spi);
619 	ae_id.sa_id.family = nl_addr_get_family (daddr);
620 	ae_id.sa_id.proto  = protocol;
621 
622 	if (!(msg = nlmsg_alloc_simple(XFRM_MSG_GETAE, 0)))
623 		return -NLE_NOMEM;
624 
625 	if (nlmsg_append(msg, &ae_id, sizeof(ae_id), NLMSG_ALIGNTO) < 0)
626 		goto nla_put_failure;
627 
628 	mark.m  =   mark_mask;
629 	mark.v  =   mark_value;
630 	NLA_PUT (msg, XFRMA_MARK, sizeof (struct xfrmnl_mark), &mark);
631 
632 	*result = msg;
633 	return 0;
634 
635 nla_put_failure:
636 	nlmsg_free(msg);
637 	return -NLE_MSGSIZE;
638 }
639 
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)640 int xfrmnl_ae_get_kernel(struct nl_sock* sock, struct nl_addr* daddr, unsigned int spi, unsigned int protocol,
641                          unsigned int mark_mask, unsigned int mark_value, struct xfrmnl_ae** result)
642 {
643 	struct nl_msg *msg = NULL;
644 	struct nl_object *obj;
645 	int err;
646 
647 	if ((err = xfrmnl_ae_build_get_request(daddr, spi, protocol, mark_mask, mark_value, &msg)) < 0)
648 		return err;
649 
650 	err = nl_send_auto(sock, msg);
651 	nlmsg_free(msg);
652 	if (err < 0)
653 		return err;
654 
655 	if ((err = nl_pickup(sock, &xfrm_ae_msg_parser, &obj)) < 0)
656 		return err;
657 
658 	/* We have used xfrm_ae_msg_parser(), object is definitely a xfrm ae */
659 	*result = (struct xfrmnl_ae *) obj;
660 
661 	/* If an object has been returned, we also need to wait for the ACK */
662 	if (err == 0 && obj)
663 		nl_wait_for_ack(sock);
664 
665 	return 0;
666 }
667 
668 /** @} */
669 
670 /**
671  * @name Attributes
672  * @{
673  */
674 
__assign_addr(struct xfrmnl_ae * ae,struct nl_addr ** pos,struct nl_addr * new,int flag,int nocheck)675 static inline int __assign_addr(struct xfrmnl_ae* ae, struct nl_addr **pos,
676 					struct nl_addr *new, int flag, int nocheck)
677 {
678 	if (!nocheck) {
679 		if (ae->ce_mask & XFRM_AE_ATTR_FAMILY) {
680 			if (nl_addr_get_family (new) != ae->sa_id.family)
681 				return -NLE_AF_MISMATCH;
682 		} else {
683 			ae->sa_id.family = nl_addr_get_family (new);
684 			ae->ce_mask |= XFRM_AE_ATTR_FAMILY;
685 		}
686 	}
687 
688 	if (*pos)
689 		nl_addr_put(*pos);
690 
691 	nl_addr_get(new);
692 	*pos = new;
693 
694 	ae->ce_mask |= flag;
695 
696 	return 0;
697 }
698 
699 
xfrmnl_ae_get_daddr(struct xfrmnl_ae * ae)700 struct nl_addr* xfrmnl_ae_get_daddr (struct xfrmnl_ae* ae)
701 {
702 	if (ae->ce_mask & XFRM_AE_ATTR_DADDR)
703 		return ae->sa_id.daddr;
704 	else
705 		return NULL;
706 }
707 
xfrmnl_ae_set_daddr(struct xfrmnl_ae * ae,struct nl_addr * addr)708 int xfrmnl_ae_set_daddr (struct xfrmnl_ae* ae, struct nl_addr* addr)
709 {
710 	return __assign_addr(ae, &ae->sa_id.daddr, addr, XFRM_AE_ATTR_DADDR, 0);
711 }
712 
xfrmnl_ae_get_spi(struct xfrmnl_ae * ae)713 int xfrmnl_ae_get_spi (struct xfrmnl_ae* ae)
714 {
715 	if (ae->ce_mask & XFRM_AE_ATTR_SPI)
716 		return ae->sa_id.spi;
717 	else
718 		return -1;
719 }
720 
xfrmnl_ae_set_spi(struct xfrmnl_ae * ae,unsigned int spi)721 int xfrmnl_ae_set_spi (struct xfrmnl_ae* ae, unsigned int spi)
722 {
723 	ae->sa_id.spi = spi;
724 	ae->ce_mask |= XFRM_AE_ATTR_SPI;
725 
726 	return 0;
727 }
728 
xfrmnl_ae_get_family(struct xfrmnl_ae * ae)729 int xfrmnl_ae_get_family (struct xfrmnl_ae* ae)
730 {
731 	if (ae->ce_mask & XFRM_AE_ATTR_FAMILY)
732 		return ae->sa_id.family;
733 	else
734 		return -1;
735 }
736 
xfrmnl_ae_set_family(struct xfrmnl_ae * ae,unsigned int family)737 int xfrmnl_ae_set_family (struct xfrmnl_ae* ae, unsigned int family)
738 {
739 	ae->sa_id.family = family;
740 	ae->ce_mask |= XFRM_AE_ATTR_FAMILY;
741 
742 	return 0;
743 }
744 
xfrmnl_ae_get_proto(struct xfrmnl_ae * ae)745 int xfrmnl_ae_get_proto (struct xfrmnl_ae* ae)
746 {
747 	if (ae->ce_mask & XFRM_AE_ATTR_PROTO)
748 		return ae->sa_id.proto;
749 	else
750 		return -1;
751 }
752 
xfrmnl_ae_set_proto(struct xfrmnl_ae * ae,unsigned int protocol)753 int xfrmnl_ae_set_proto (struct xfrmnl_ae* ae, unsigned int protocol)
754 {
755 	ae->sa_id.proto = protocol;
756 	ae->ce_mask |= XFRM_AE_ATTR_PROTO;
757 
758 	return 0;
759 }
760 
xfrmnl_ae_get_saddr(struct xfrmnl_ae * ae)761 struct nl_addr* xfrmnl_ae_get_saddr (struct xfrmnl_ae* ae)
762 {
763 	if (ae->ce_mask & XFRM_AE_ATTR_SADDR)
764 		return ae->saddr;
765 	else
766 		return NULL;
767 }
768 
xfrmnl_ae_set_saddr(struct xfrmnl_ae * ae,struct nl_addr * addr)769 int xfrmnl_ae_set_saddr (struct xfrmnl_ae* ae, struct nl_addr* addr)
770 {
771 	return 	__assign_addr(ae, &ae->saddr, addr, XFRM_AE_ATTR_SADDR, 1);
772 }
773 
xfrmnl_ae_get_flags(struct xfrmnl_ae * ae)774 int xfrmnl_ae_get_flags (struct xfrmnl_ae* ae)
775 {
776 	if (ae->ce_mask & XFRM_AE_ATTR_FLAGS)
777 		return ae->flags;
778 	else
779 		return -1;
780 }
781 
xfrmnl_ae_set_flags(struct xfrmnl_ae * ae,unsigned int flags)782 int xfrmnl_ae_set_flags (struct xfrmnl_ae* ae, unsigned int flags)
783 {
784 	ae->flags = flags;
785 	ae->ce_mask |= XFRM_AE_ATTR_FLAGS;
786 
787 	return 0;
788 }
789 
xfrmnl_ae_get_reqid(struct xfrmnl_ae * ae)790 int xfrmnl_ae_get_reqid (struct xfrmnl_ae* ae)
791 {
792 	if (ae->ce_mask & XFRM_AE_ATTR_REQID)
793 		return ae->reqid;
794 	else
795 		return -1;
796 }
797 
xfrmnl_ae_set_reqid(struct xfrmnl_ae * ae,unsigned int reqid)798 int xfrmnl_ae_set_reqid (struct xfrmnl_ae* ae, unsigned int reqid)
799 {
800 	ae->reqid = reqid;
801 	ae->ce_mask |= XFRM_AE_ATTR_REQID;
802 
803 	return 0;
804 }
805 
xfrmnl_ae_get_mark(struct xfrmnl_ae * ae,unsigned int * mark_mask,unsigned int * mark_value)806 int xfrmnl_ae_get_mark (struct xfrmnl_ae* ae, unsigned int* mark_mask, unsigned int* mark_value)
807 {
808 	if (mark_mask == NULL || mark_value == NULL)
809 		return -1;
810 
811 	if (ae->ce_mask & XFRM_AE_ATTR_MARK)
812 	{
813 		*mark_mask  =   ae->mark.m;
814 		*mark_value  =   ae->mark.v;
815 
816 		return 0;
817 	}
818 	else
819 		return -1;
820 }
821 
xfrmnl_ae_set_mark(struct xfrmnl_ae * ae,unsigned int value,unsigned int mask)822 int xfrmnl_ae_set_mark (struct xfrmnl_ae* ae, unsigned int value, unsigned int mask)
823 {
824 	ae->mark.v  = value;
825 	ae->mark.m  = mask;
826 	ae->ce_mask |= XFRM_AE_ATTR_MARK;
827 
828 	return 0;
829 }
830 
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)831 int xfrmnl_ae_get_curlifetime (struct xfrmnl_ae* ae, unsigned long long int* curr_bytes,
832                                unsigned long long int* curr_packets, unsigned long long int* curr_add_time,
833                                unsigned long long int* curr_use_time)
834 {
835 	if (curr_bytes == NULL || curr_packets == NULL || curr_add_time == NULL || curr_use_time == NULL)
836 		return -1;
837 
838 	if (ae->ce_mask & XFRM_AE_ATTR_LIFETIME)
839 	{
840 		*curr_bytes     =   ae->lifetime_cur.bytes;
841 		*curr_packets   =   ae->lifetime_cur.packets;
842 		*curr_add_time  =   ae->lifetime_cur.add_time;
843 		*curr_use_time  =   ae->lifetime_cur.use_time;
844 
845 		return 0;
846 	}
847 	else
848 		return -1;
849 }
850 
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)851 int xfrmnl_ae_set_curlifetime (struct xfrmnl_ae* ae, unsigned long long int curr_bytes,
852                                unsigned long long int curr_packets, unsigned long long int curr_add_time,
853                                unsigned long long int curr_use_time)
854 {
855 	ae->lifetime_cur.bytes = curr_bytes;
856 	ae->lifetime_cur.packets = curr_packets;
857 	ae->lifetime_cur.add_time = curr_add_time;
858 	ae->lifetime_cur.use_time = curr_use_time;
859 	ae->ce_mask |= XFRM_AE_ATTR_LIFETIME;
860 
861 	return 0;
862 }
863 
xfrmnl_ae_get_replay_maxage(struct xfrmnl_ae * ae)864 int xfrmnl_ae_get_replay_maxage (struct xfrmnl_ae* ae)
865 {
866 	if (ae->ce_mask & XFRM_AE_ATTR_REPLAY_MAXAGE)
867 		return ae->replay_maxage;
868 	else
869 		return -1;
870 }
871 
xfrmnl_ae_set_replay_maxage(struct xfrmnl_ae * ae,unsigned int replay_maxage)872 int xfrmnl_ae_set_replay_maxage (struct xfrmnl_ae* ae, unsigned int replay_maxage)
873 {
874 	ae->replay_maxage  = replay_maxage;
875 	ae->ce_mask |= XFRM_AE_ATTR_REPLAY_MAXAGE;
876 
877 	return 0;
878 }
879 
xfrmnl_ae_get_replay_maxdiff(struct xfrmnl_ae * ae)880 int xfrmnl_ae_get_replay_maxdiff (struct xfrmnl_ae* ae)
881 {
882 	if (ae->ce_mask & XFRM_AE_ATTR_REPLAY_MAXDIFF)
883 		return ae->replay_maxdiff;
884 	else
885 		return -1;
886 }
887 
xfrmnl_ae_set_replay_maxdiff(struct xfrmnl_ae * ae,unsigned int replay_maxdiff)888 int xfrmnl_ae_set_replay_maxdiff (struct xfrmnl_ae* ae, unsigned int replay_maxdiff)
889 {
890 	ae->replay_maxdiff  = replay_maxdiff;
891 	ae->ce_mask |= XFRM_AE_ATTR_REPLAY_MAXDIFF;
892 
893 	return 0;
894 }
895 
xfrmnl_ae_get_replay_state(struct xfrmnl_ae * ae,unsigned int * oseq,unsigned int * seq,unsigned int * bmp)896 int xfrmnl_ae_get_replay_state (struct xfrmnl_ae* ae, unsigned int* oseq, unsigned int* seq, unsigned int* bmp)
897 {
898 	if (ae->ce_mask & XFRM_AE_ATTR_REPLAY_STATE)
899 	{
900 		if (ae->replay_state_esn == NULL)
901 		{
902 			*oseq   =   ae->replay_state.oseq;
903 			*seq    =   ae->replay_state.seq;
904 			*bmp    =   ae->replay_state.bitmap;
905 
906 			return 0;
907 		}
908 		else
909 		{
910 			return -1;
911 		}
912 	}
913 	else
914 		return -1;
915 }
916 
xfrmnl_ae_set_replay_state(struct xfrmnl_ae * ae,unsigned int oseq,unsigned int seq,unsigned int bitmap)917 int xfrmnl_ae_set_replay_state (struct xfrmnl_ae* ae, unsigned int oseq, unsigned int seq, unsigned int bitmap)
918 {
919 	ae->replay_state.oseq = oseq;
920 	ae->replay_state.seq = seq;
921 	ae->replay_state.bitmap = bitmap;
922 	ae->ce_mask |= XFRM_AE_ATTR_REPLAY_STATE;
923 
924 	return 0;
925 }
926 
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)927 int xfrmnl_ae_get_replay_state_esn(struct xfrmnl_ae* ae, unsigned int* oseq, unsigned int* seq, unsigned int* oseq_hi,
928                                    unsigned int* seq_hi, unsigned int* replay_window, unsigned int* bmp_len, unsigned int* bmp)
929 {
930 	if (ae->ce_mask & XFRM_AE_ATTR_REPLAY_STATE)
931 	{
932 		if (ae->replay_state_esn)
933 		{
934 			*oseq   =   ae->replay_state_esn->oseq;
935 			*seq    =   ae->replay_state_esn->seq;
936 			*oseq_hi=   ae->replay_state_esn->oseq_hi;
937 			*seq_hi =   ae->replay_state_esn->seq_hi;
938 			*replay_window  =   ae->replay_state_esn->replay_window;
939 			*bmp_len        =   ae->replay_state_esn->bmp_len; // In number of 32 bit words
940 			memcpy (bmp, ae->replay_state_esn->bmp, ae->replay_state_esn->bmp_len * sizeof (uint32_t));
941 
942 			return 0;
943 		}
944 		else
945 		{
946 			return -1;
947 		}
948 	}
949 	else
950 		return -1;
951 }
952 
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)953 int xfrmnl_ae_set_replay_state_esn(struct xfrmnl_ae* ae, unsigned int oseq, unsigned int seq,
954                                    unsigned int oseq_hi, unsigned int seq_hi, unsigned int replay_window,
955                                    unsigned int bmp_len, unsigned int* bmp)
956 {
957 	/* Free the old replay ESN state and allocate new one */
958 	if (ae->replay_state_esn)
959 		free (ae->replay_state_esn);
960 
961 	if ((ae->replay_state_esn = calloc (1, sizeof (struct xfrmnl_replay_state_esn) + sizeof (uint32_t) * bmp_len)) == NULL)
962 		return -1;
963 
964 	ae->replay_state_esn->oseq = oseq;
965 	ae->replay_state_esn->seq = seq;
966 	ae->replay_state_esn->oseq_hi = oseq_hi;
967 	ae->replay_state_esn->seq_hi = seq_hi;
968 	ae->replay_state_esn->replay_window = replay_window;
969 	ae->replay_state_esn->bmp_len = bmp_len; // In number of 32 bit words
970 	memcpy (ae->replay_state_esn->bmp, bmp, bmp_len * sizeof (uint32_t));
971 	ae->ce_mask |= XFRM_AE_ATTR_REPLAY_STATE;
972 
973 	return 0;
974 }
975 
976 /** @} */
977 
978 static struct nl_object_ops xfrm_ae_obj_ops = {
979 	.oo_name        =   "xfrm/ae",
980 	.oo_size        =   sizeof(struct xfrmnl_ae),
981 	.oo_free_data   =   xfrm_ae_free_data,
982 	.oo_clone       =   xfrm_ae_clone,
983 	.oo_dump        =   {
984 	                        [NL_DUMP_LINE]      =   xfrm_ae_dump_line,
985 	                        [NL_DUMP_DETAILS]   =   xfrm_ae_dump_details,
986 	                        [NL_DUMP_STATS]     =   xfrm_ae_dump_stats,
987 	                    },
988 	.oo_compare     =   xfrm_ae_compare,
989 	.oo_attrs2str   =   xfrm_ae_attrs2str,
990 	.oo_id_attrs    =   (XFRM_AE_ATTR_DADDR | XFRM_AE_ATTR_SPI | XFRM_AE_ATTR_PROTO),
991 };
992 
993 /** @} */
994 
995