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