You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
851 lines
19 KiB
851 lines
19 KiB
/*
|
|
* lib/route/link/macsec.c MACsec Link Info
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation version 2.1
|
|
* of the License.
|
|
*
|
|
* Copyright (c) 2016 Sabrina Dubroca <sd@queasysnail.net>
|
|
*/
|
|
|
|
/**
|
|
* @ingroup link
|
|
* @defgroup macsec MACsec
|
|
* MACsec link module
|
|
*
|
|
* @details
|
|
* \b Link Type Name: "macsec"
|
|
*
|
|
* @route_doc{link_macsec, MACsec Documentation}
|
|
*
|
|
* @{
|
|
*/
|
|
#include <netlink-private/netlink.h>
|
|
#include <netlink/netlink.h>
|
|
#include <netlink/attr.h>
|
|
#include <netlink/utils.h>
|
|
#include <netlink/object.h>
|
|
#include <netlink/route/rtnl.h>
|
|
#include <netlink/route/link/macsec.h>
|
|
#include <netlink-private/route/link/api.h>
|
|
#include <netlink-private/utils.h>
|
|
|
|
#include <linux/if_macsec.h>
|
|
|
|
/** @cond SKIP */
|
|
#define MACSEC_ATTR_SCI (1 << 0)
|
|
#define MACSEC_ATTR_ICV_LEN (1 << 1)
|
|
#define MACSEC_ATTR_CIPHER_SUITE (1 << 2)
|
|
#define MACSEC_ATTR_WINDOW (1 << 3)
|
|
#define MACSEC_ATTR_ENCODING_SA (1 << 4)
|
|
#define MACSEC_ATTR_ENCRYPT (1 << 5)
|
|
#define MACSEC_ATTR_PROTECT (1 << 6)
|
|
#define MACSEC_ATTR_INC_SCI (1 << 7)
|
|
#define MACSEC_ATTR_ES (1 << 8)
|
|
#define MACSEC_ATTR_SCB (1 << 9)
|
|
#define MACSEC_ATTR_REPLAY_PROTECT (1 << 10)
|
|
#define MACSEC_ATTR_VALIDATION (1 << 11)
|
|
#define MACSEC_ATTR_PORT (1 << 12)
|
|
|
|
struct macsec_info {
|
|
int ifindex;
|
|
uint64_t sci;
|
|
uint16_t port;
|
|
uint64_t cipher_suite;
|
|
uint16_t icv_len;
|
|
uint32_t window;
|
|
enum macsec_validation_type validate;
|
|
uint8_t encoding_sa;
|
|
|
|
uint8_t send_sci, end_station, scb, replay_protect, protect, encrypt;
|
|
|
|
uint32_t ce_mask;
|
|
};
|
|
|
|
#define DEFAULT_ICV_LEN 16
|
|
|
|
/** @endcond */
|
|
|
|
static struct nla_policy macsec_policy[IFLA_MACSEC_MAX+1] = {
|
|
[IFLA_MACSEC_SCI] = { .type = NLA_U64 },
|
|
[IFLA_MACSEC_ICV_LEN] = { .type = NLA_U8 },
|
|
[IFLA_MACSEC_CIPHER_SUITE] = { .type = NLA_U64 },
|
|
[IFLA_MACSEC_WINDOW] = { .type = NLA_U32 },
|
|
[IFLA_MACSEC_ENCODING_SA] = { .type = NLA_U8 },
|
|
[IFLA_MACSEC_ENCRYPT] = { .type = NLA_U8 },
|
|
[IFLA_MACSEC_PROTECT] = { .type = NLA_U8 },
|
|
[IFLA_MACSEC_INC_SCI] = { .type = NLA_U8 },
|
|
[IFLA_MACSEC_ES] = { .type = NLA_U8 },
|
|
[IFLA_MACSEC_SCB] = { .type = NLA_U8 },
|
|
[IFLA_MACSEC_REPLAY_PROTECT] = { .type = NLA_U8 },
|
|
[IFLA_MACSEC_VALIDATION] = { .type = NLA_U8 },
|
|
};
|
|
|
|
/**
|
|
* @name MACsec Object
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* Allocate link object of type MACsec
|
|
*
|
|
* @return Allocated link object or NULL.
|
|
*/
|
|
static int macsec_alloc(struct rtnl_link *link)
|
|
{
|
|
struct macsec_info *info;
|
|
|
|
if (!link->l_info) {
|
|
link->l_info = malloc(sizeof(struct macsec_info));
|
|
if (!link->l_info)
|
|
return -NLE_NOMEM;
|
|
}
|
|
|
|
memset(link->l_info, 0, sizeof(struct macsec_info));
|
|
info = link->l_info;
|
|
|
|
info->cipher_suite = MACSEC_DEFAULT_CIPHER_ID;
|
|
info->icv_len = DEFAULT_ICV_LEN;
|
|
info->ce_mask = MACSEC_ATTR_CIPHER_SUITE | MACSEC_ATTR_ICV_LEN;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int macsec_parse(struct rtnl_link *link, struct nlattr *data,
|
|
struct nlattr *xstats)
|
|
{
|
|
struct nlattr *tb[IFLA_MACSEC_MAX+1];
|
|
struct macsec_info *info;
|
|
int err;
|
|
|
|
NL_DBG(3, "Parsing MACsec link info\n");
|
|
|
|
if ((err = nla_parse_nested(tb, IFLA_MACSEC_MAX, data, macsec_policy)) < 0)
|
|
goto errout;
|
|
|
|
if ((err = macsec_alloc(link)) < 0)
|
|
goto errout;
|
|
|
|
info = link->l_info;
|
|
|
|
if (tb[IFLA_MACSEC_SCI]) {
|
|
info->sci = nla_get_u64(tb[IFLA_MACSEC_SCI]);
|
|
info->ce_mask |= MACSEC_ATTR_SCI;
|
|
}
|
|
|
|
if (tb[IFLA_MACSEC_PROTECT]) {
|
|
info->protect = nla_get_u8(tb[IFLA_MACSEC_PROTECT]);
|
|
info->ce_mask |= MACSEC_ATTR_PROTECT;
|
|
}
|
|
|
|
if (tb[IFLA_MACSEC_CIPHER_SUITE]) {
|
|
info->cipher_suite = nla_get_u64(tb[IFLA_MACSEC_CIPHER_SUITE]);
|
|
info->ce_mask |= MACSEC_ATTR_CIPHER_SUITE;
|
|
}
|
|
|
|
if (tb[IFLA_MACSEC_ICV_LEN]) {
|
|
info->icv_len = nla_get_u8(tb[IFLA_MACSEC_ICV_LEN]);
|
|
info->ce_mask |= MACSEC_ATTR_ICV_LEN;
|
|
}
|
|
|
|
if (tb[IFLA_MACSEC_ENCODING_SA]) {
|
|
info->encoding_sa = nla_get_u8(tb[IFLA_MACSEC_ENCODING_SA]);
|
|
info->ce_mask |= MACSEC_ATTR_ENCODING_SA;
|
|
}
|
|
|
|
if (tb[IFLA_MACSEC_VALIDATION]) {
|
|
info->validate = nla_get_u8(tb[IFLA_MACSEC_VALIDATION]);
|
|
info->ce_mask |= MACSEC_ATTR_VALIDATION;
|
|
}
|
|
|
|
if (tb[IFLA_MACSEC_ENCRYPT]) {
|
|
info->encrypt = nla_get_u8(tb[IFLA_MACSEC_ENCRYPT]);
|
|
info->ce_mask |= MACSEC_ATTR_ENCRYPT;
|
|
}
|
|
|
|
if (tb[IFLA_MACSEC_INC_SCI]) {
|
|
info->send_sci = nla_get_u8(tb[IFLA_MACSEC_INC_SCI]);
|
|
info->ce_mask |= MACSEC_ATTR_INC_SCI;
|
|
}
|
|
|
|
if (tb[IFLA_MACSEC_ES]) {
|
|
info->end_station = nla_get_u8(tb[IFLA_MACSEC_ES]);
|
|
info->ce_mask |= MACSEC_ATTR_ES;
|
|
}
|
|
|
|
if (tb[IFLA_MACSEC_SCB]) {
|
|
info->scb = nla_get_u8(tb[IFLA_MACSEC_SCB]);
|
|
info->ce_mask |= MACSEC_ATTR_SCB;
|
|
}
|
|
|
|
if (tb[IFLA_MACSEC_REPLAY_PROTECT]) {
|
|
info->replay_protect = nla_get_u8(tb[IFLA_MACSEC_REPLAY_PROTECT]);
|
|
info->ce_mask |= MACSEC_ATTR_REPLAY_PROTECT;
|
|
}
|
|
|
|
if (tb[IFLA_MACSEC_WINDOW]) {
|
|
info->window = nla_get_u32(tb[IFLA_MACSEC_WINDOW]);
|
|
info->ce_mask |= MACSEC_ATTR_WINDOW;
|
|
}
|
|
|
|
err = 0;
|
|
errout:
|
|
return err;
|
|
}
|
|
|
|
static void macsec_free(struct rtnl_link *link)
|
|
{
|
|
free(link->l_info);
|
|
link->l_info = NULL;
|
|
}
|
|
|
|
static const char *values_on_off[] = { "off", "on" };
|
|
|
|
static const char *VALIDATE_STR[] = {
|
|
[MACSEC_VALIDATE_DISABLED] = "disabled",
|
|
[MACSEC_VALIDATE_CHECK] = "check",
|
|
[MACSEC_VALIDATE_STRICT] = "strict",
|
|
};
|
|
|
|
static char *replay_protect_str(char *buf, uint8_t replay_protect, uint8_t window)
|
|
{
|
|
if (replay_protect == 1) {
|
|
sprintf(buf, "replay_protect on window %d", window);
|
|
} else if (replay_protect == 0) {
|
|
sprintf(buf, "replay_protect off");
|
|
} else {
|
|
buf[0] = '\0';
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
/** @cond SKIP */
|
|
#define PRINT_FLAG(buf, i, field, c) ({ if (i->field == 1) *buf++ = c; })
|
|
/** @endcond */
|
|
static char *flags_str(char *buf, unsigned char len, struct macsec_info *info)
|
|
{
|
|
char *tmp = buf;
|
|
memset(tmp, 0, len);
|
|
|
|
PRINT_FLAG(tmp, info, protect, 'P');
|
|
PRINT_FLAG(tmp, info, encrypt, 'E');
|
|
PRINT_FLAG(tmp, info, send_sci, 'S');
|
|
PRINT_FLAG(tmp, info, end_station, 'e');
|
|
PRINT_FLAG(tmp, info, scb, 's');
|
|
PRINT_FLAG(tmp, info, replay_protect, 'R');
|
|
|
|
*tmp++ = ' ';
|
|
*tmp++ = 'v';
|
|
switch (info->validate) {
|
|
case MACSEC_VALIDATE_DISABLED:
|
|
*tmp++ = 'd';
|
|
break;
|
|
case MACSEC_VALIDATE_CHECK:
|
|
*tmp++ = 'c';
|
|
break;
|
|
case MACSEC_VALIDATE_STRICT:
|
|
*tmp++ = 's';
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
sprintf(tmp, " %d", info->encoding_sa);
|
|
|
|
return buf;
|
|
}
|
|
|
|
static void macsec_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
char tmp[128];
|
|
|
|
nl_dump(p, "sci %016llx <%s>", ntohll(info->sci), flags_str(tmp, sizeof(tmp), info));
|
|
}
|
|
|
|
static void macsec_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
char tmp[128];
|
|
|
|
nl_dump(p, " sci %016llx protect %s encoding_sa %d encrypt %s send_sci %s validate %s %s\n",
|
|
ntohll(info->sci), values_on_off[info->protect], info->encoding_sa, values_on_off[info->encrypt], values_on_off[info->send_sci],
|
|
VALIDATE_STR[info->validate],
|
|
replay_protect_str(tmp, info->replay_protect, info->window));
|
|
nl_dump(p, " cipher suite: %016llx, icv_len %d\n",
|
|
info->cipher_suite, info->icv_len);
|
|
}
|
|
|
|
static int macsec_clone(struct rtnl_link *dst, struct rtnl_link *src)
|
|
{
|
|
struct macsec_info *copy, *info = src->l_info;
|
|
int err;
|
|
|
|
dst->l_info = NULL;
|
|
if ((err = rtnl_link_set_type(dst, "macsec")) < 0)
|
|
return err;
|
|
copy = dst->l_info;
|
|
|
|
if (!info || !copy)
|
|
return -NLE_NOMEM;
|
|
|
|
memcpy(copy, info, sizeof(struct macsec_info));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int macsec_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
struct nlattr *data;
|
|
|
|
if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
|
|
return -NLE_MSGSIZE;
|
|
|
|
if (info->ce_mask & MACSEC_ATTR_SCI)
|
|
NLA_PUT_U64(msg, IFLA_MACSEC_SCI, info->sci);
|
|
else if (info->ce_mask & MACSEC_ATTR_PORT)
|
|
NLA_PUT_U16(msg, IFLA_MACSEC_PORT, htons(info->port));
|
|
|
|
if ((info->ce_mask & MACSEC_ATTR_ENCRYPT))
|
|
NLA_PUT_U8(msg, IFLA_MACSEC_ENCRYPT, info->encrypt);
|
|
|
|
if (info->cipher_suite != MACSEC_DEFAULT_CIPHER_ID || info->icv_len != DEFAULT_ICV_LEN) {
|
|
NLA_PUT_U64(msg, IFLA_MACSEC_CIPHER_SUITE, info->cipher_suite);
|
|
NLA_PUT_U8(msg, IFLA_MACSEC_ICV_LEN, info->icv_len);
|
|
}
|
|
|
|
if ((info->ce_mask & MACSEC_ATTR_INC_SCI))
|
|
NLA_PUT_U8(msg, IFLA_MACSEC_INC_SCI, info->send_sci);
|
|
|
|
if ((info->ce_mask & MACSEC_ATTR_ES))
|
|
NLA_PUT_U8(msg, IFLA_MACSEC_ES, info->end_station);
|
|
|
|
if ((info->ce_mask & MACSEC_ATTR_SCB))
|
|
NLA_PUT_U8(msg, IFLA_MACSEC_SCB, info->scb);
|
|
|
|
if ((info->ce_mask & MACSEC_ATTR_PROTECT))
|
|
NLA_PUT_U8(msg, IFLA_MACSEC_PROTECT, info->protect);
|
|
|
|
if ((info->ce_mask & MACSEC_ATTR_REPLAY_PROTECT)) {
|
|
if (info->replay_protect && !(info->ce_mask & MACSEC_ATTR_WINDOW))
|
|
return -NLE_INVAL;
|
|
|
|
NLA_PUT_U8(msg, IFLA_MACSEC_REPLAY_PROTECT, info->replay_protect);
|
|
NLA_PUT_U32(msg, IFLA_MACSEC_WINDOW, info->window);
|
|
}
|
|
|
|
if ((info->ce_mask & MACSEC_ATTR_VALIDATION))
|
|
NLA_PUT_U8(msg, IFLA_MACSEC_VALIDATION, info->validate);
|
|
|
|
if ((info->ce_mask & MACSEC_ATTR_ENCODING_SA))
|
|
NLA_PUT_U8(msg, IFLA_MACSEC_ENCODING_SA, info->encoding_sa);
|
|
|
|
nla_nest_end(msg, data);
|
|
|
|
return 0;
|
|
|
|
nla_put_failure:
|
|
return -NLE_MSGSIZE;
|
|
}
|
|
|
|
static int macsec_compare(struct rtnl_link *link_a, struct rtnl_link *link_b,
|
|
int flags)
|
|
{
|
|
struct macsec_info *a = link_a->l_info;
|
|
struct macsec_info *b = link_b->l_info;
|
|
int diff = 0;
|
|
uint32_t attrs = flags & LOOSE_COMPARISON ? b->ce_mask : ~0;
|
|
|
|
#define MACSEC_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, MACSEC_ATTR_##ATTR, a, b, EXPR)
|
|
|
|
if (a->ce_mask & MACSEC_ATTR_SCI && b->ce_mask & MACSEC_ATTR_SCI)
|
|
diff |= MACSEC_DIFF(SCI, a->sci != b->sci);
|
|
else if (a->ce_mask & MACSEC_ATTR_PORT && b->ce_mask & MACSEC_ATTR_PORT)
|
|
diff |= MACSEC_DIFF(PORT, a->port != b->port);
|
|
|
|
if (a->ce_mask & MACSEC_ATTR_CIPHER_SUITE && b->ce_mask & MACSEC_ATTR_CIPHER_SUITE) {
|
|
diff |= MACSEC_DIFF(ICV_LEN, a->icv_len != b->icv_len);
|
|
diff |= MACSEC_DIFF(CIPHER_SUITE, a->cipher_suite != b->cipher_suite);
|
|
}
|
|
|
|
if (a->ce_mask & MACSEC_ATTR_REPLAY_PROTECT && b->ce_mask & MACSEC_ATTR_REPLAY_PROTECT) {
|
|
int d = MACSEC_DIFF(REPLAY_PROTECT, a->replay_protect != b->replay_protect);
|
|
if (a->replay_protect && b->replay_protect)
|
|
d |= MACSEC_DIFF(WINDOW, a->window != b->window);
|
|
diff |= d;
|
|
}
|
|
|
|
diff |= MACSEC_DIFF(ENCODING_SA, a->encoding_sa != b->encoding_sa);
|
|
diff |= MACSEC_DIFF(ENCRYPT, a->encrypt != b->encrypt);
|
|
diff |= MACSEC_DIFF(PROTECT, a->protect != b->protect);
|
|
diff |= MACSEC_DIFF(INC_SCI, a->send_sci != b->send_sci);
|
|
diff |= MACSEC_DIFF(ES, a->end_station != b->end_station);
|
|
diff |= MACSEC_DIFF(SCB, a->scb != b->scb);
|
|
diff |= MACSEC_DIFF(VALIDATION, a->validate != b->validate);
|
|
#undef MACSEC_DIFF
|
|
|
|
return diff;
|
|
}
|
|
|
|
|
|
static struct rtnl_link_info_ops macsec_info_ops = {
|
|
.io_name = "macsec",
|
|
.io_alloc = macsec_alloc,
|
|
.io_parse = macsec_parse,
|
|
.io_dump = {
|
|
[NL_DUMP_LINE] = macsec_dump_line,
|
|
[NL_DUMP_DETAILS] = macsec_dump_details,
|
|
},
|
|
.io_clone = macsec_clone,
|
|
.io_put_attrs = macsec_put_attrs,
|
|
.io_free = macsec_free,
|
|
.io_compare = macsec_compare,
|
|
};
|
|
|
|
static void __init macsec_init(void)
|
|
{
|
|
rtnl_link_register_info(&macsec_info_ops);
|
|
}
|
|
|
|
static void __exit macsec_exit(void)
|
|
{
|
|
rtnl_link_unregister_info(&macsec_info_ops);
|
|
}
|
|
|
|
/** @cond SKIP */
|
|
#define IS_MACSEC_LINK_ASSERT(link) \
|
|
if ((link)->l_info_ops != &macsec_info_ops) { \
|
|
APPBUG("Link is not a MACsec link. set type \"macsec\" first."); \
|
|
return -NLE_OPNOTSUPP; \
|
|
}
|
|
/** @endcond */
|
|
|
|
struct rtnl_link *rtnl_link_macsec_alloc(void)
|
|
{
|
|
struct rtnl_link *link = rtnl_link_alloc();
|
|
|
|
if (!link)
|
|
return NULL;
|
|
|
|
if (rtnl_link_set_type(link, "macsec") < 0) {
|
|
rtnl_link_put(link);
|
|
return NULL;
|
|
}
|
|
|
|
return link;
|
|
}
|
|
|
|
/**
|
|
* Set SCI
|
|
* @arg link Link object
|
|
* @arg sci Secure Channel Identifier in network byte order
|
|
*
|
|
* @return 0 on success or a negative error code.
|
|
*/
|
|
int rtnl_link_macsec_set_sci(struct rtnl_link *link, uint64_t sci)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
info->sci = sci;
|
|
info->ce_mask |= MACSEC_ATTR_SCI;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Get SCI
|
|
* @arg link Link object
|
|
* @arg sci On return points to the Secure Channel Identifier
|
|
* in network byte order
|
|
*
|
|
* @return 0 on success or a negative error code.
|
|
*/
|
|
int rtnl_link_macsec_get_sci(struct rtnl_link *link, uint64_t *sci)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
if (!(info->ce_mask & MACSEC_ATTR_SCI))
|
|
return -NLE_NOATTR;
|
|
|
|
if (sci)
|
|
*sci = info->sci;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Set port identifier
|
|
* @arg link Link object
|
|
* @arg port Port identifier in host byte order
|
|
*
|
|
* @return 0 on success or a negative error code.
|
|
*/
|
|
int rtnl_link_macsec_set_port(struct rtnl_link *link, uint16_t port)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
info->port = port;
|
|
info->ce_mask |= MACSEC_ATTR_PORT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Get port identifier
|
|
* @arg link Link object
|
|
* @arg port On return points to the port identifier in host byte order
|
|
*
|
|
* @return 0 on success or a negative error code.
|
|
*/
|
|
int rtnl_link_macsec_get_port(struct rtnl_link *link, uint16_t *port)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
if (!(info->ce_mask & MACSEC_ATTR_PORT))
|
|
return -NLE_NOATTR;
|
|
|
|
if (port)
|
|
*port = info->port;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rtnl_link_macsec_set_cipher_suite(struct rtnl_link *link, uint64_t cipher_suite)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
info->cipher_suite = cipher_suite;
|
|
info->ce_mask |= MACSEC_ATTR_CIPHER_SUITE;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rtnl_link_macsec_get_cipher_suite(struct rtnl_link *link, uint64_t *cs)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
if (!(info->ce_mask & MACSEC_ATTR_CIPHER_SUITE))
|
|
return -NLE_NOATTR;
|
|
|
|
if (cs)
|
|
*cs = info->cipher_suite;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rtnl_link_macsec_set_icv_len(struct rtnl_link *link, uint16_t icv_len)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
if (icv_len > MACSEC_STD_ICV_LEN)
|
|
return -NLE_INVAL;
|
|
|
|
info->icv_len = icv_len;
|
|
info->ce_mask |= MACSEC_ATTR_ICV_LEN;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rtnl_link_macsec_get_icv_len(struct rtnl_link *link, uint16_t *icv_len)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
if (!(info->ce_mask & MACSEC_ATTR_ICV_LEN))
|
|
return -NLE_NOATTR;
|
|
|
|
if (icv_len)
|
|
*icv_len = info->icv_len;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rtnl_link_macsec_set_protect(struct rtnl_link *link, uint8_t protect)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
if (protect > 1)
|
|
return -NLE_INVAL;
|
|
|
|
info->protect = protect;
|
|
info->ce_mask |= MACSEC_ATTR_PROTECT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rtnl_link_macsec_get_protect(struct rtnl_link *link, uint8_t *protect)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
if (!(info->ce_mask & MACSEC_ATTR_PROTECT))
|
|
return -NLE_NOATTR;
|
|
|
|
if (protect)
|
|
*protect = info->protect;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rtnl_link_macsec_set_encrypt(struct rtnl_link *link, uint8_t encrypt)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
if (encrypt > 1)
|
|
return -NLE_INVAL;
|
|
|
|
info->encrypt = encrypt;
|
|
info->ce_mask |= MACSEC_ATTR_ENCRYPT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rtnl_link_macsec_get_encrypt(struct rtnl_link *link, uint8_t *encrypt)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
if (!(info->ce_mask & MACSEC_ATTR_ENCRYPT))
|
|
return -NLE_NOATTR;
|
|
|
|
if (encrypt)
|
|
*encrypt = info->encrypt;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rtnl_link_macsec_set_encoding_sa(struct rtnl_link *link, uint8_t encoding_sa)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
if (encoding_sa > 3)
|
|
return -NLE_INVAL;
|
|
|
|
info->encoding_sa = encoding_sa;
|
|
info->ce_mask |= MACSEC_ATTR_ENCODING_SA;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rtnl_link_macsec_get_encoding_sa(struct rtnl_link *link, uint8_t *encoding_sa)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
if (!(info->ce_mask & MACSEC_ATTR_ENCODING_SA))
|
|
return -NLE_NOATTR;
|
|
|
|
if (encoding_sa)
|
|
*encoding_sa = info->encoding_sa;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rtnl_link_macsec_set_validation_type(struct rtnl_link *link, enum macsec_validation_type validate)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
if (validate > 1)
|
|
return -NLE_INVAL;
|
|
|
|
info->validate = validate;
|
|
info->ce_mask |= MACSEC_ATTR_VALIDATION;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rtnl_link_macsec_get_validation_type(struct rtnl_link *link, enum macsec_validation_type *validate)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
if (!(info->ce_mask & MACSEC_ATTR_VALIDATION))
|
|
return -NLE_NOATTR;
|
|
|
|
if (validate)
|
|
*validate = info->validate;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rtnl_link_macsec_set_replay_protect(struct rtnl_link *link, uint8_t replay_protect)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
if (replay_protect > 1)
|
|
return -NLE_INVAL;
|
|
|
|
info->replay_protect = replay_protect;
|
|
info->ce_mask |= MACSEC_ATTR_REPLAY_PROTECT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rtnl_link_macsec_get_replay_protect(struct rtnl_link *link, uint8_t *replay_protect)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
if (!(info->ce_mask & MACSEC_ATTR_REPLAY_PROTECT))
|
|
return -NLE_NOATTR;
|
|
|
|
if (replay_protect)
|
|
*replay_protect = info->replay_protect;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rtnl_link_macsec_set_window(struct rtnl_link *link, uint32_t window)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
info->window = window;
|
|
info->ce_mask |= MACSEC_ATTR_WINDOW;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rtnl_link_macsec_get_window(struct rtnl_link *link, uint32_t *window)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
if (!(info->ce_mask & MACSEC_ATTR_WINDOW))
|
|
return -NLE_NOATTR;
|
|
|
|
if (window)
|
|
*window = info->window;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rtnl_link_macsec_set_send_sci(struct rtnl_link *link, uint8_t send_sci)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
if (send_sci > 1)
|
|
return -NLE_INVAL;
|
|
|
|
info->send_sci = send_sci;
|
|
info->ce_mask |= MACSEC_ATTR_INC_SCI;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rtnl_link_macsec_get_send_sci(struct rtnl_link *link, uint8_t *send_sci)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
if (!(info->ce_mask & MACSEC_ATTR_INC_SCI))
|
|
return -NLE_NOATTR;
|
|
|
|
if (send_sci)
|
|
*send_sci = info->send_sci;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rtnl_link_macsec_set_end_station(struct rtnl_link *link, uint8_t end_station)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
if (end_station > 1)
|
|
return -NLE_INVAL;
|
|
|
|
info->end_station = end_station;
|
|
info->ce_mask |= MACSEC_ATTR_ES;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rtnl_link_macsec_get_end_station(struct rtnl_link *link, uint8_t *es)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
if (!(info->ce_mask & MACSEC_ATTR_ES))
|
|
return -NLE_NOATTR;
|
|
|
|
if (es)
|
|
*es = info->end_station;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rtnl_link_macsec_set_scb(struct rtnl_link *link, uint8_t scb)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
if (scb > 1)
|
|
return -NLE_INVAL;
|
|
|
|
info->scb = scb;
|
|
info->ce_mask |= MACSEC_ATTR_SCB;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rtnl_link_macsec_get_scb(struct rtnl_link *link, uint8_t *scb)
|
|
{
|
|
struct macsec_info *info = link->l_info;
|
|
|
|
IS_MACSEC_LINK_ASSERT(link);
|
|
|
|
if (!(info->ce_mask & MACSEC_ATTR_SCB))
|
|
return -NLE_NOATTR;
|
|
|
|
if (scb)
|
|
*scb = info->scb;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/** @} */
|
|
|
|
/** @} */
|