19#include "nl-default.h"
21#include <linux/if_macsec.h>
23#include <netlink/netlink.h>
24#include <netlink/attr.h>
25#include <netlink/utils.h>
26#include <netlink/object.h>
27#include <netlink/route/rtnl.h>
28#include <netlink/route/link/macsec.h>
32#include "nl-priv-dynamic-core/nl-core.h"
35#define MACSEC_ATTR_SCI (1 << 0)
36#define MACSEC_ATTR_ICV_LEN (1 << 1)
37#define MACSEC_ATTR_CIPHER_SUITE (1 << 2)
38#define MACSEC_ATTR_WINDOW (1 << 3)
39#define MACSEC_ATTR_ENCODING_SA (1 << 4)
40#define MACSEC_ATTR_ENCRYPT (1 << 5)
41#define MACSEC_ATTR_PROTECT (1 << 6)
42#define MACSEC_ATTR_INC_SCI (1 << 7)
43#define MACSEC_ATTR_ES (1 << 8)
44#define MACSEC_ATTR_SCB (1 << 9)
45#define MACSEC_ATTR_REPLAY_PROTECT (1 << 10)
46#define MACSEC_ATTR_VALIDATION (1 << 11)
47#define MACSEC_ATTR_PORT (1 << 12)
48#define MACSEC_ATTR_OFFLOAD (1 << 13)
54 uint64_t cipher_suite;
57 enum macsec_validation_type validate;
60 uint8_t send_sci, end_station, scb, replay_protect, protect, encrypt, offload;
65#define DEFAULT_ICV_LEN 16
95static int macsec_alloc(
struct rtnl_link *link)
97 struct macsec_info *info;
100 link->l_info = malloc(
sizeof(
struct macsec_info));
105 memset(link->l_info, 0,
sizeof(
struct macsec_info));
108 info->cipher_suite = MACSEC_DEFAULT_CIPHER_ID;
109 info->icv_len = DEFAULT_ICV_LEN;
110 info->ce_mask = MACSEC_ATTR_CIPHER_SUITE | MACSEC_ATTR_ICV_LEN;
115static int macsec_parse(
struct rtnl_link *link,
struct nlattr *data,
116 struct nlattr *xstats)
118 struct nlattr *tb[IFLA_MACSEC_MAX+1];
119 struct macsec_info *info;
122 NL_DBG(3,
"Parsing MACsec link info\n");
127 if ((err = macsec_alloc(link)) < 0)
132 if (tb[IFLA_MACSEC_SCI]) {
134 info->ce_mask |= MACSEC_ATTR_SCI;
137 if (tb[IFLA_MACSEC_PROTECT]) {
138 info->protect =
nla_get_u8(tb[IFLA_MACSEC_PROTECT]);
139 info->ce_mask |= MACSEC_ATTR_PROTECT;
142 if (tb[IFLA_MACSEC_CIPHER_SUITE]) {
143 info->cipher_suite =
nla_get_u64(tb[IFLA_MACSEC_CIPHER_SUITE]);
144 info->ce_mask |= MACSEC_ATTR_CIPHER_SUITE;
147 if (tb[IFLA_MACSEC_ICV_LEN]) {
148 info->icv_len =
nla_get_u8(tb[IFLA_MACSEC_ICV_LEN]);
149 info->ce_mask |= MACSEC_ATTR_ICV_LEN;
152 if (tb[IFLA_MACSEC_ENCODING_SA]) {
153 info->encoding_sa =
nla_get_u8(tb[IFLA_MACSEC_ENCODING_SA]);
154 info->ce_mask |= MACSEC_ATTR_ENCODING_SA;
157 if (tb[IFLA_MACSEC_VALIDATION]) {
158 info->validate =
nla_get_u8(tb[IFLA_MACSEC_VALIDATION]);
159 info->ce_mask |= MACSEC_ATTR_VALIDATION;
162 if (tb[IFLA_MACSEC_ENCRYPT]) {
163 info->encrypt =
nla_get_u8(tb[IFLA_MACSEC_ENCRYPT]);
164 info->ce_mask |= MACSEC_ATTR_ENCRYPT;
167 if (tb[IFLA_MACSEC_OFFLOAD]) {
168 info->offload =
nla_get_u8(tb[IFLA_MACSEC_OFFLOAD]);
169 info->ce_mask |= MACSEC_ATTR_OFFLOAD;
172 if (tb[IFLA_MACSEC_INC_SCI]) {
173 info->send_sci =
nla_get_u8(tb[IFLA_MACSEC_INC_SCI]);
174 info->ce_mask |= MACSEC_ATTR_INC_SCI;
177 if (tb[IFLA_MACSEC_ES]) {
178 info->end_station =
nla_get_u8(tb[IFLA_MACSEC_ES]);
179 info->ce_mask |= MACSEC_ATTR_ES;
182 if (tb[IFLA_MACSEC_SCB]) {
184 info->ce_mask |= MACSEC_ATTR_SCB;
187 if (tb[IFLA_MACSEC_REPLAY_PROTECT]) {
188 info->replay_protect =
nla_get_u8(tb[IFLA_MACSEC_REPLAY_PROTECT]);
189 info->ce_mask |= MACSEC_ATTR_REPLAY_PROTECT;
192 if (tb[IFLA_MACSEC_WINDOW]) {
193 info->window =
nla_get_u32(tb[IFLA_MACSEC_WINDOW]);
194 info->ce_mask |= MACSEC_ATTR_WINDOW;
202static void macsec_free(
struct rtnl_link *link)
208static const char *values_on_off[] = {
"off",
"on" };
210static const char *VALIDATE_STR[] = {
211 [MACSEC_VALIDATE_DISABLED] =
"disabled",
212 [MACSEC_VALIDATE_CHECK] =
"check",
213 [MACSEC_VALIDATE_STRICT] =
"strict",
216static char *replay_protect_str(
char *buf, uint8_t replay_protect, uint8_t window)
218 if (replay_protect == 1) {
219 sprintf(buf,
"replay_protect on window %d", window);
220 }
else if (replay_protect == 0) {
221 sprintf(buf,
"replay_protect off");
230#define PRINT_FLAG(buf, i, field, c) ({ if (i->field == 1) *buf++ = c; })
232static char *flags_str(
char *buf,
unsigned char len,
struct macsec_info *info)
237 PRINT_FLAG(tmp, info, protect,
'P');
238 PRINT_FLAG(tmp, info, encrypt,
'E');
239 PRINT_FLAG(tmp, info, send_sci,
'S');
240 PRINT_FLAG(tmp, info, end_station,
'e');
241 PRINT_FLAG(tmp, info, scb,
's');
242 PRINT_FLAG(tmp, info, replay_protect,
'R');
246 switch (info->validate) {
247 case MACSEC_VALIDATE_DISABLED:
250 case MACSEC_VALIDATE_CHECK:
253 case MACSEC_VALIDATE_STRICT:
260 sprintf(tmp,
" %d", info->encoding_sa);
267 struct macsec_info *info = link->l_info;
270 nl_dump(p,
"sci %016llx <%s>", (
long long unsigned)ntohll(info->sci),
271 flags_str(tmp,
sizeof(tmp), info));
276 struct macsec_info *info = link->l_info;
280 " sci %016llx protect %s encoding_sa %d encrypt %s send_sci %s validate %s %s\n",
281 (
long long unsigned)ntohll(info->sci),
282 values_on_off[info->protect], info->encoding_sa,
283 values_on_off[info->encrypt], values_on_off[info->send_sci],
284 VALIDATE_STR[info->validate],
285 replay_protect_str(tmp, info->replay_protect, info->window));
286 nl_dump(p,
" cipher suite: %016llx, icv_len %d\n",
287 (
long long unsigned)info->cipher_suite, info->icv_len);
292 struct macsec_info *copy, *info = src->l_info;
303 memcpy(copy, info,
sizeof(
struct macsec_info));
308static int macsec_put_attrs(
struct nl_msg *msg,
struct rtnl_link *link)
310 struct macsec_info *info = link->l_info;
316 if (info->ce_mask & MACSEC_ATTR_SCI)
318 else if (info->ce_mask & MACSEC_ATTR_PORT)
319 NLA_PUT_U16(msg, IFLA_MACSEC_PORT, htons(info->port));
321 if ((info->ce_mask & MACSEC_ATTR_ENCRYPT))
322 NLA_PUT_U8(msg, IFLA_MACSEC_ENCRYPT, info->encrypt);
324 if ((info->ce_mask & MACSEC_ATTR_OFFLOAD))
325 NLA_PUT_U8(msg, IFLA_MACSEC_OFFLOAD, info->offload);
327 if (info->cipher_suite != MACSEC_DEFAULT_CIPHER_ID || info->icv_len != DEFAULT_ICV_LEN) {
328 NLA_PUT_U64(msg, IFLA_MACSEC_CIPHER_SUITE, info->cipher_suite);
329 NLA_PUT_U8(msg, IFLA_MACSEC_ICV_LEN, info->icv_len);
332 if ((info->ce_mask & MACSEC_ATTR_INC_SCI))
333 NLA_PUT_U8(msg, IFLA_MACSEC_INC_SCI, info->send_sci);
335 if ((info->ce_mask & MACSEC_ATTR_ES))
336 NLA_PUT_U8(msg, IFLA_MACSEC_ES, info->end_station);
338 if ((info->ce_mask & MACSEC_ATTR_SCB))
341 if ((info->ce_mask & MACSEC_ATTR_PROTECT))
342 NLA_PUT_U8(msg, IFLA_MACSEC_PROTECT, info->protect);
344 if ((info->ce_mask & MACSEC_ATTR_REPLAY_PROTECT)) {
345 if (info->replay_protect && !(info->ce_mask & MACSEC_ATTR_WINDOW))
348 NLA_PUT_U8(msg, IFLA_MACSEC_REPLAY_PROTECT, info->replay_protect);
349 NLA_PUT_U32(msg, IFLA_MACSEC_WINDOW, info->window);
352 if ((info->ce_mask & MACSEC_ATTR_VALIDATION))
353 NLA_PUT_U8(msg, IFLA_MACSEC_VALIDATION, info->validate);
355 if ((info->ce_mask & MACSEC_ATTR_ENCODING_SA))
356 NLA_PUT_U8(msg, IFLA_MACSEC_ENCODING_SA, info->encoding_sa);
369 struct macsec_info *a = link_a->l_info;
370 struct macsec_info *b = link_b->l_info;
372 uint32_t attrs = flags & LOOSE_COMPARISON ? b->ce_mask :
375#define _DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ATTR, a, b, EXPR)
376 if (a->ce_mask & MACSEC_ATTR_SCI && b->ce_mask & MACSEC_ATTR_SCI)
377 diff |= _DIFF(MACSEC_ATTR_SCI, a->sci != b->sci);
378 else if (a->ce_mask & MACSEC_ATTR_PORT && b->ce_mask & MACSEC_ATTR_PORT)
379 diff |= _DIFF(MACSEC_ATTR_PORT, a->port != b->port);
381 if (a->ce_mask & MACSEC_ATTR_CIPHER_SUITE &&
382 b->ce_mask & MACSEC_ATTR_CIPHER_SUITE) {
383 diff |= _DIFF(MACSEC_ATTR_ICV_LEN, a->icv_len != b->icv_len);
384 diff |= _DIFF(MACSEC_ATTR_CIPHER_SUITE,
385 a->cipher_suite != b->cipher_suite);
388 if (a->ce_mask & MACSEC_ATTR_REPLAY_PROTECT &&
389 b->ce_mask & MACSEC_ATTR_REPLAY_PROTECT) {
390 int d = _DIFF(MACSEC_ATTR_REPLAY_PROTECT,
391 a->replay_protect != b->replay_protect);
392 if (a->replay_protect && b->replay_protect) {
393 d |= _DIFF(MACSEC_ATTR_WINDOW, a->window != b->window);
398 diff |= _DIFF(MACSEC_ATTR_ENCODING_SA,
399 a->encoding_sa != b->encoding_sa);
400 diff |= _DIFF(MACSEC_ATTR_ENCRYPT, a->encrypt != b->encrypt);
401 diff |= _DIFF(MACSEC_ATTR_PROTECT, a->protect != b->protect);
402 diff |= _DIFF(MACSEC_ATTR_INC_SCI, a->send_sci != b->send_sci);
403 diff |= _DIFF(MACSEC_ATTR_ES, a->end_station != b->end_station);
404 diff |= _DIFF(MACSEC_ATTR_SCB, a->scb != b->scb);
405 diff |= _DIFF(MACSEC_ATTR_VALIDATION, a->validate != b->validate);
414 .io_alloc = macsec_alloc,
415 .io_parse = macsec_parse,
420 .io_clone = macsec_clone,
421 .io_put_attrs = macsec_put_attrs,
422 .io_free = macsec_free,
423 .io_compare = macsec_compare,
426static void _nl_init macsec_init(
void)
431static void _nl_exit macsec_exit(
void)
437#define IS_MACSEC_LINK_ASSERT(link) \
438 if ((link)->l_info_ops != &macsec_info_ops) { \
439 APPBUG("Link is not a MACsec link. set type \"macsec\" first."); \
440 return -NLE_OPNOTSUPP; \
444struct rtnl_link *rtnl_link_macsec_alloc(
void)
468 struct macsec_info *info = link->l_info;
470 IS_MACSEC_LINK_ASSERT(link);
473 info->ce_mask |= MACSEC_ATTR_SCI;
488 struct macsec_info *info = link->l_info;
490 IS_MACSEC_LINK_ASSERT(link);
492 if (!(info->ce_mask & MACSEC_ATTR_SCI))
510 struct macsec_info *info = link->l_info;
512 IS_MACSEC_LINK_ASSERT(link);
515 info->ce_mask |= MACSEC_ATTR_PORT;
529 struct macsec_info *info = link->l_info;
531 IS_MACSEC_LINK_ASSERT(link);
533 if (!(info->ce_mask & MACSEC_ATTR_PORT))
542int rtnl_link_macsec_set_cipher_suite(
struct rtnl_link *link, uint64_t cipher_suite)
544 struct macsec_info *info = link->l_info;
546 IS_MACSEC_LINK_ASSERT(link);
548 info->cipher_suite = cipher_suite;
549 info->ce_mask |= MACSEC_ATTR_CIPHER_SUITE;
554int rtnl_link_macsec_get_cipher_suite(
struct rtnl_link *link, uint64_t *cs)
556 struct macsec_info *info = link->l_info;
558 IS_MACSEC_LINK_ASSERT(link);
560 if (!(info->ce_mask & MACSEC_ATTR_CIPHER_SUITE))
564 *cs = info->cipher_suite;
569int rtnl_link_macsec_set_icv_len(
struct rtnl_link *link, uint16_t icv_len)
571 struct macsec_info *info = link->l_info;
573 IS_MACSEC_LINK_ASSERT(link);
575 if (icv_len > MACSEC_STD_ICV_LEN)
578 info->icv_len = icv_len;
579 info->ce_mask |= MACSEC_ATTR_ICV_LEN;
584int rtnl_link_macsec_get_icv_len(
struct rtnl_link *link, uint16_t *icv_len)
586 struct macsec_info *info = link->l_info;
588 IS_MACSEC_LINK_ASSERT(link);
590 if (!(info->ce_mask & MACSEC_ATTR_ICV_LEN))
594 *icv_len = info->icv_len;
599int rtnl_link_macsec_set_protect(
struct rtnl_link *link, uint8_t protect)
601 struct macsec_info *info = link->l_info;
603 IS_MACSEC_LINK_ASSERT(link);
608 info->protect = protect;
609 info->ce_mask |= MACSEC_ATTR_PROTECT;
614int rtnl_link_macsec_get_protect(
struct rtnl_link *link, uint8_t *protect)
616 struct macsec_info *info = link->l_info;
618 IS_MACSEC_LINK_ASSERT(link);
620 if (!(info->ce_mask & MACSEC_ATTR_PROTECT))
624 *protect = info->protect;
629int rtnl_link_macsec_set_encrypt(
struct rtnl_link *link, uint8_t encrypt)
631 struct macsec_info *info = link->l_info;
633 IS_MACSEC_LINK_ASSERT(link);
638 info->encrypt = encrypt;
639 info->ce_mask |= MACSEC_ATTR_ENCRYPT;
644int rtnl_link_macsec_get_encrypt(
struct rtnl_link *link, uint8_t *encrypt)
646 struct macsec_info *info = link->l_info;
648 IS_MACSEC_LINK_ASSERT(link);
650 if (!(info->ce_mask & MACSEC_ATTR_ENCRYPT))
654 *encrypt = info->encrypt;
659int rtnl_link_macsec_set_offload(
struct rtnl_link *link, uint8_t offload)
661 struct macsec_info *info = link->l_info;
663 IS_MACSEC_LINK_ASSERT(link);
665 info->offload = offload;
666 info->ce_mask |= MACSEC_ATTR_OFFLOAD;
671int rtnl_link_macsec_get_offload(
struct rtnl_link *link, uint8_t *offload)
673 struct macsec_info *info = link->l_info;
675 IS_MACSEC_LINK_ASSERT(link);
677 if (!(info->ce_mask & MACSEC_ATTR_OFFLOAD))
681 *offload = info->offload;
686int rtnl_link_macsec_set_encoding_sa(
struct rtnl_link *link, uint8_t encoding_sa)
688 struct macsec_info *info = link->l_info;
690 IS_MACSEC_LINK_ASSERT(link);
695 info->encoding_sa = encoding_sa;
696 info->ce_mask |= MACSEC_ATTR_ENCODING_SA;
701int rtnl_link_macsec_get_encoding_sa(
struct rtnl_link *link, uint8_t *encoding_sa)
703 struct macsec_info *info = link->l_info;
705 IS_MACSEC_LINK_ASSERT(link);
707 if (!(info->ce_mask & MACSEC_ATTR_ENCODING_SA))
711 *encoding_sa = info->encoding_sa;
716int rtnl_link_macsec_set_validation_type(
struct rtnl_link *link,
enum macsec_validation_type validate)
718 struct macsec_info *info = link->l_info;
720 IS_MACSEC_LINK_ASSERT(link);
722 if (validate > MACSEC_VALIDATE_MAX)
725 info->validate = validate;
726 info->ce_mask |= MACSEC_ATTR_VALIDATION;
731int rtnl_link_macsec_get_validation_type(
struct rtnl_link *link,
enum macsec_validation_type *validate)
733 struct macsec_info *info = link->l_info;
735 IS_MACSEC_LINK_ASSERT(link);
737 if (!(info->ce_mask & MACSEC_ATTR_VALIDATION))
741 *validate = info->validate;
746int rtnl_link_macsec_set_replay_protect(
struct rtnl_link *link, uint8_t replay_protect)
748 struct macsec_info *info = link->l_info;
750 IS_MACSEC_LINK_ASSERT(link);
752 if (replay_protect > 1)
755 info->replay_protect = replay_protect;
756 info->ce_mask |= MACSEC_ATTR_REPLAY_PROTECT;
761int rtnl_link_macsec_get_replay_protect(
struct rtnl_link *link, uint8_t *replay_protect)
763 struct macsec_info *info = link->l_info;
765 IS_MACSEC_LINK_ASSERT(link);
767 if (!(info->ce_mask & MACSEC_ATTR_REPLAY_PROTECT))
771 *replay_protect = info->replay_protect;
776int rtnl_link_macsec_set_window(
struct rtnl_link *link, uint32_t window)
778 struct macsec_info *info = link->l_info;
780 IS_MACSEC_LINK_ASSERT(link);
782 info->window = window;
783 info->ce_mask |= MACSEC_ATTR_WINDOW;
788int rtnl_link_macsec_get_window(
struct rtnl_link *link, uint32_t *window)
790 struct macsec_info *info = link->l_info;
792 IS_MACSEC_LINK_ASSERT(link);
794 if (!(info->ce_mask & MACSEC_ATTR_WINDOW))
798 *window = info->window;
803int rtnl_link_macsec_set_send_sci(
struct rtnl_link *link, uint8_t send_sci)
805 struct macsec_info *info = link->l_info;
807 IS_MACSEC_LINK_ASSERT(link);
812 info->send_sci = send_sci;
813 info->ce_mask |= MACSEC_ATTR_INC_SCI;
818int rtnl_link_macsec_get_send_sci(
struct rtnl_link *link, uint8_t *send_sci)
820 struct macsec_info *info = link->l_info;
822 IS_MACSEC_LINK_ASSERT(link);
824 if (!(info->ce_mask & MACSEC_ATTR_INC_SCI))
828 *send_sci = info->send_sci;
833int rtnl_link_macsec_set_end_station(
struct rtnl_link *link, uint8_t end_station)
835 struct macsec_info *info = link->l_info;
837 IS_MACSEC_LINK_ASSERT(link);
842 info->end_station = end_station;
843 info->ce_mask |= MACSEC_ATTR_ES;
848int rtnl_link_macsec_get_end_station(
struct rtnl_link *link, uint8_t *es)
850 struct macsec_info *info = link->l_info;
852 IS_MACSEC_LINK_ASSERT(link);
854 if (!(info->ce_mask & MACSEC_ATTR_ES))
858 *es = info->end_station;
863int rtnl_link_macsec_set_scb(
struct rtnl_link *link, uint8_t scb)
865 struct macsec_info *info = link->l_info;
867 IS_MACSEC_LINK_ASSERT(link);
873 info->ce_mask |= MACSEC_ATTR_SCB;
878int rtnl_link_macsec_get_scb(
struct rtnl_link *link, uint8_t *scb)
880 struct macsec_info *info = link->l_info;
882 IS_MACSEC_LINK_ASSERT(link);
884 if (!(info->ce_mask & MACSEC_ATTR_SCB))
uint32_t nla_get_u32(const struct nlattr *nla)
Return payload of 32 bit integer attribute.
#define NLA_PUT_U16(msg, attrtype, value)
Add 16 bit integer attribute to netlink message.
#define NLA_PUT_U8(msg, attrtype, value)
Add 8 bit integer attribute to netlink message.
uint64_t nla_get_u64(const struct nlattr *nla)
Return payload of u64 attribute.
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
uint8_t nla_get_u8(const struct nlattr *nla)
Return value of 8 bit integer attribute.
struct nlattr * nla_nest_start(struct nl_msg *msg, int attrtype)
Start a new level of nested attributes.
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, const struct nla_policy *policy)
Create attribute index based on nested attribute.
#define NLA_PUT_U64(msg, attrtype, value)
Add 64 bit integer attribute to netlink message.
int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
Finalize nesting of attributes.
int rtnl_link_register_info(struct rtnl_link_info_ops *ops)
Register operations for a link info type.
int rtnl_link_unregister_info(struct rtnl_link_info_ops *ops)
Unregister operations for a link info type.
struct rtnl_link * rtnl_link_alloc(void)
Allocate link object.
void rtnl_link_put(struct rtnl_link *link)
Release a link object reference.
int rtnl_link_set_type(struct rtnl_link *link, const char *type)
Set type of link object.
int rtnl_link_macsec_set_sci(struct rtnl_link *link, uint64_t sci)
Set SCI.
int rtnl_link_macsec_get_sci(struct rtnl_link *link, uint64_t *sci)
Get SCI.
int rtnl_link_macsec_set_port(struct rtnl_link *link, uint16_t port)
Set port identifier.
int rtnl_link_macsec_get_port(struct rtnl_link *link, uint16_t *port)
Get port identifier.
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
@ NL_DUMP_LINE
Dump object briefly on one line.
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
Attribute validation policy.
uint16_t type
Type of attribute or NLA_UNSPEC.
Available operations to modules implementing a link info type.
char * io_name
Name of link info type, must match name on kernel side.