libnl 3.7.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 <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
144static struct nl_object_ops xfrm_ae_obj_ops;
145/** @endcond */
146
147
148static 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
162static 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
192static 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 */
249static 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
264static 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
275static 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
286char* 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
291int xfrmnl_ae_str2flag(const char *name)
292{
293 return __str2flags(name, ae_flags, ARRAY_SIZE(ae_flags));
294}
295/** @} */
296
297static 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
363static void xfrm_ae_dump_details(struct nl_object *a, struct nl_dump_params *p)
364{
365 xfrm_ae_dump_line(a, p);
366}
367
368static 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
374static 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
433nla_put_failure:
434 nlmsg_free(msg);
435 return -NLE_MSGSIZE;
436}
437
438/**
439 * @name XFRM AE Update
440 * @{
441 */
442
443int 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
466struct xfrmnl_ae* xfrmnl_ae_alloc(void)
467{
468 return (struct xfrmnl_ae*) nl_object_alloc(&xfrm_ae_obj_ops);
469}
470
471void xfrmnl_ae_put(struct xfrmnl_ae* ae)
472{
473 nl_object_put((struct nl_object *) ae);
474}
475
476/** @} */
477
478static 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
488int 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
576errout:
577 xfrmnl_ae_put(ae);
578 return err;
579}
580
581static 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
601int 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
635nla_put_failure:
636 nlmsg_free(msg);
637 return -NLE_MSGSIZE;
638}
639
640int 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
675static 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
700struct 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
708int 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
713int 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
721int 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
729int 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
737int 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
745int 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
753int 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
761struct 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
769int 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
774int 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
782int 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
790int 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
798int 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
806int 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
822int 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
831int 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
851int 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
864int 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
872int 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
880int 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
888int 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
896int 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
917int 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
927int 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
953int 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
978static 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
struct nl_addr * nl_addr_get(struct nl_addr *addr)
Increase the reference counter of an abstract address.
Definition: addr.c:522
struct nl_addr * nl_addr_build(int family, const void *buf, size_t size)
Allocate abstract address based on a binary address.
Definition: addr.c:211
void * nl_addr_get_binary_addr(const struct nl_addr *addr)
Get binary address of abstract address object.
Definition: addr.c:940
int nl_addr_cmp(const struct nl_addr *a, const struct nl_addr *b)
Compare abstract addresses.
Definition: addr.c:584
struct nl_addr * nl_addr_clone(const struct nl_addr *addr)
Clone existing abstract address object.
Definition: addr.c:492
int nl_addr_get_family(const struct nl_addr *addr)
Return address family.
Definition: addr.c:892
char * nl_addr2str(const struct nl_addr *addr, char *buf, size_t size)
Convert abstract address object to character string.
Definition: addr.c:998
unsigned int nl_addr_get_len(const struct nl_addr *addr)
Get length of binary address of abstract address object.
Definition: addr.c:952
void nl_addr_put(struct nl_addr *addr)
Decrease the reference counter of an abstract address.
Definition: addr.c:538
void * nla_data(const struct nlattr *nla)
Return pointer to the payload section.
Definition: attr.c:114
#define NLA_PUT(msg, attrtype, attrlen, data)
Add unspecific attribute to netlink message.
Definition: attr.h:159
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
Definition: attr.h:230
@ NLA_U32
32 bit integer
Definition: attr.h:37
struct nl_msg * nlmsg_alloc_simple(int nlmsgtype, int flags)
Allocate a new netlink message.
Definition: msg.c:341
void * nlmsg_data(const struct nlmsghdr *nlh)
Return pointer to message payload.
Definition: msg.c:100
void nlmsg_free(struct nl_msg *msg)
Release a reference from an netlink message.
Definition: msg.c:558
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:208
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:442
void nl_object_put(struct nl_object *obj)
Release a reference from an object.
Definition: object.c:214
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:48
int nl_send_auto(struct nl_sock *sk, struct nl_msg *msg)
Finalize and transmit Netlink message.
Definition: nl.c:510
int nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg)
Definition: nl.c:1241
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:1172
int nl_wait_for_ack(struct nl_sock *sk)
Wait for ACK.
Definition: nl.c:1106
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Definition: utils.c:955
@ NL_DUMP_STATS
Dump all attributes including statistics.
Definition: types.h:18
@ NL_DUMP_LINE
Dump object briefly on one line.
Definition: types.h:16
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
Definition: types.h:17
Dumping parameters.
Definition: types.h:28
Attribute validation policy.
Definition: attr.h:63
uint16_t minlen
Minimal length of payload required.
Definition: attr.h:68