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 
144 static struct nl_object_ops xfrm_ae_obj_ops;
145 /** @endcond */
146 
147 
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 
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 
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 
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 
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 
291 int xfrmnl_ae_str2flag(const char *name)
292 {
293  return __str2flags(name, ae_flags, ARRAY_SIZE(ae_flags));
294 }
295 /** @} */
296 
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 
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 
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 
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 
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 
466 struct xfrmnl_ae* xfrmnl_ae_alloc(void)
467 {
468  return (struct xfrmnl_ae*) nl_object_alloc(&xfrm_ae_obj_ops);
469 }
470 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
void * nl_addr_get_binary_addr(const struct nl_addr *addr)
Get binary address of abstract address object.
Definition: addr.c:935
char * nl_addr2str(const struct nl_addr *addr, char *buf, size_t size)
Convert abstract address object to character string.
Definition: addr.c:993
int nl_addr_cmp(const struct nl_addr *a, const struct nl_addr *b)
Compare abstract addresses.
Definition: addr.c:579
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
int nl_addr_get_family(const struct nl_addr *addr)
Return address family.
Definition: addr.c:887
struct nl_addr * nl_addr_clone(const struct nl_addr *addr)
Clone existing abstract address object.
Definition: addr.c:487
struct nl_addr * nl_addr_get(struct nl_addr *addr)
Increase the reference counter of an abstract address.
Definition: addr.c:517
unsigned int nl_addr_get_len(const struct nl_addr *addr)
Get length of binary address of abstract address object.
Definition: addr.c:947
void nl_addr_put(struct nl_addr *addr)
Decrease the reference counter of an abstract address.
Definition: addr.c:533
#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
void * nla_data(const struct nlattr *nla)
Return pointer to the payload section.
Definition: attr.c:114
@ 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_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 * nlmsg_data(const struct nlmsghdr *nlh)
Return pointer to message payload.
Definition: msg.c:100
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