libnl: /data/src/libnl3/lib/xfrm/ae.c Source File

libnl 3.10.0

ae.c
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
142struct xfrmnl_sa_id {
143 struct nl_addr* daddr;
144 uint32_t spi;
145 uint16_t family;
146 uint8_t proto;
147};
148
149struct 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
177static struct nl_object_ops xfrm_ae_obj_ops;
178/** @endcond */
179
180
181static 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
195static 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
225static 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 */
286static 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
301static 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
312static 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
323char* 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
328int xfrmnl_ae_str2flag(const char *name)
329{
330 return __str2flags(name, ae_flags, ARRAY_SIZE(ae_flags));
331}
332/** @} */
333
334static 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
401static void xfrm_ae_dump_details(struct nl_object *a, struct nl_dump_params *p)
402{
403 xfrm_ae_dump_line(a, p);
404}
405
406static 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
412static 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
471nla_put_failure:
472 nlmsg_free(msg);
473 return -NLE_MSGSIZE;
474}
475
476/**
477 * @name XFRM AE Update
478 * @{
479 */
480
481int 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
504struct xfrmnl_ae* xfrmnl_ae_alloc(void)
505{
506 return (struct xfrmnl_ae*) nl_object_alloc(&xfrm_ae_obj_ops);
507}
508
509void xfrmnl_ae_put(struct xfrmnl_ae* ae)
510{
511 nl_object_put((struct nl_object *) ae);
512}
513
514/** @} */
515
516static 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
526int 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
615static 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
635int 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
669nla_put_failure:
670 nlmsg_free(msg);
671 return -NLE_MSGSIZE;
672}
673
674int 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
709static 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
734struct 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
742int 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
747int 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
755int 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
763int 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
771int 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
779int 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
787int 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
795struct 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
803int 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
808int 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
816int 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
824int 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
832int 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
840int 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
856int 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
865int 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
885int 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
898int 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
906int 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
914int 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
922int 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
930int 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
951int 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
961int 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
987int 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
1012static 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
nl_addr_get
struct nl_addr * nl_addr_get(struct nl_addr *addr)
Increase the reference counter of an abstract address.
Definition addr.c:525
nl_addr_get_binary_addr
void * nl_addr_get_binary_addr(const struct nl_addr *addr)
Get binary address of abstract address object.
Definition addr.c:943
nl_addr_cmp
int nl_addr_cmp(const struct nl_addr *a, const struct nl_addr *b)
Compare abstract addresses.
Definition addr.c:587
nl_addr_clone
struct nl_addr * nl_addr_clone(const struct nl_addr *addr)
Clone existing abstract address object.
Definition addr.c:495
nl_addr_get_family
int nl_addr_get_family(const struct nl_addr *addr)
Return address family.
Definition addr.c:895
nl_addr2str
char * nl_addr2str(const struct nl_addr *addr, char *buf, size_t size)
Convert abstract address object to character string.
Definition addr.c:1001
nl_addr_get_len
unsigned int nl_addr_get_len(const struct nl_addr *addr)
Get length of binary address of abstract address object.
Definition addr.c:955
nl_addr_put
void nl_addr_put(struct nl_addr *addr)
Decrease the reference counter of an abstract address.
Definition addr.c:541
nla_data
void * nla_data(const struct nlattr *nla)
Return pointer to the payload section.
Definition attr.c:119
NLA_PUT
#define NLA_PUT(msg, attrtype, attrlen, data)
Add unspecific attribute to netlink message.
Definition attr.h:159
NLA_PUT_U32
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
Definition attr.h:230
NLA_U32
@ NLA_U32
32 bit integer
Definition attr.h:37
nlmsg_alloc_simple
struct nl_msg * nlmsg_alloc_simple(int nlmsgtype, int flags)
Allocate a new netlink message.
Definition msg.c:352
nlmsg_data
void * nlmsg_data(const struct nlmsghdr *nlh)
Return pointer to message payload.
Definition msg.c:108
nlmsg_free
void nlmsg_free(struct nl_msg *msg)
Release a reference from an netlink message.
Definition msg.c:572
nlmsg_parse
int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, const struct nla_policy *policy)
parse attributes of a netlink message
Definition msg.c:219
nlmsg_append
int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
Append data to tail of a netlink message.
Definition msg.c:456
nl_object_put
void nl_object_put(struct nl_object *obj)
Release a reference from an object.
Definition object.c:221
nl_object_alloc
struct nl_object * nl_object_alloc(struct nl_object_ops *ops)
Allocate a new object of kind specified by the operations handle.
Definition object.c:55
nl_send_auto
int nl_send_auto(struct nl_sock *sk, struct nl_msg *msg)
Finalize and transmit Netlink message.
Definition nl.c:515
nl_send_auto_complete
int nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg)
Definition nl.c:1247
nl_pickup
int nl_pickup(struct nl_sock *sk, int(*parser)(struct nl_cache_ops *, struct sockaddr_nl *, struct nlmsghdr *, struct nl_parser_param *), struct nl_object **result)
Pickup netlink answer, parse is and return object.
Definition nl.c:1178
nl_wait_for_ack
int nl_wait_for_ack(struct nl_sock *sk)
Wait for ACK.
Definition nl.c:1112
nl_dump
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Definition utils.c:1015
NL_DUMP_STATS
@ NL_DUMP_STATS
Dump all attributes including statistics.
Definition types.h:22
NL_DUMP_LINE
@ NL_DUMP_LINE
Dump object briefly on one line.
Definition types.h:20
NL_DUMP_DETAILS
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
Definition types.h:21
nl_dump_params
Dumping parameters.
Definition types.h:32
nla_policy
Attribute validation policy.
Definition attr.h:63
nla_policy::minlen
uint16_t minlen
Minimal length of payload required.
Definition attr.h:68
nla_policy::type
uint16_t type
Type of attribute or NLA_UNSPEC.
Definition attr.h:65
xfrmnl_lifetime_cur
Definition nl-xfrm.h:24
xfrmnl_mark
Definition nl-xfrm.h:47
xfrmnl_replay_state_esn
Definition nl-xfrm.h:37
xfrmnl_replay_state
Definition nl-xfrm.h:31