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