1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <netinet/in.h>
4 #include <linux/if_arp.h>
5 #include <linux/if_ether.h>
6 #include <linux/if_macsec.h>
7 #include <linux/genetlink.h>
9 #include "conf-parser.h"
12 #include "hexdecoct.h"
14 #include "memory-util.h"
15 #include "netlink-util.h"
16 #include "networkd-manager.h"
17 #include "path-util.h"
18 #include "socket-util.h"
19 #include "string-table.h"
20 #include "string-util.h"
23 static void security_association_clear(SecurityAssociation
*sa
) {
27 explicit_bzero_safe(sa
->key
, sa
->key_len
);
32 static void security_association_init(SecurityAssociation
*sa
) {
36 sa
->use_for_encoding
= -1;
39 static ReceiveAssociation
* macsec_receive_association_free(ReceiveAssociation
*c
) {
43 if (c
->macsec
&& c
->section
)
44 ordered_hashmap_remove(c
->macsec
->receive_associations_by_section
, c
->section
);
46 config_section_free(c
->section
);
47 security_association_clear(&c
->sa
);
52 DEFINE_SECTION_CLEANUP_FUNCTIONS(ReceiveAssociation
, macsec_receive_association_free
);
54 static int macsec_receive_association_new_static(MACsec
*s
, const char *filename
, unsigned section_line
, ReceiveAssociation
**ret
) {
55 _cleanup_(config_section_freep
) ConfigSection
*n
= NULL
;
56 _cleanup_(macsec_receive_association_freep
) ReceiveAssociation
*c
= NULL
;
62 assert(section_line
> 0);
64 r
= config_section_new(filename
, section_line
, &n
);
68 c
= ordered_hashmap_get(s
->receive_associations_by_section
, n
);
74 c
= new(ReceiveAssociation
, 1);
78 *c
= (ReceiveAssociation
) {
80 .section
= TAKE_PTR(n
),
83 security_association_init(&c
->sa
);
85 r
= ordered_hashmap_ensure_put(&s
->receive_associations_by_section
, &config_section_hash_ops
, c
->section
, c
);
94 static ReceiveChannel
* macsec_receive_channel_free(ReceiveChannel
*c
) {
99 if (c
->sci
.as_uint64
> 0)
100 ordered_hashmap_remove_value(c
->macsec
->receive_channels
, &c
->sci
.as_uint64
, c
);
103 ordered_hashmap_remove(c
->macsec
->receive_channels_by_section
, c
->section
);
106 config_section_free(c
->section
);
111 DEFINE_SECTION_CLEANUP_FUNCTIONS(ReceiveChannel
, macsec_receive_channel_free
);
113 static int macsec_receive_channel_new(MACsec
*s
, uint64_t sci
, ReceiveChannel
**ret
) {
118 c
= new(ReceiveChannel
, 1);
122 *c
= (ReceiveChannel
) {
124 .sci
.as_uint64
= sci
,
131 static int macsec_receive_channel_new_static(MACsec
*s
, const char *filename
, unsigned section_line
, ReceiveChannel
**ret
) {
132 _cleanup_(config_section_freep
) ConfigSection
*n
= NULL
;
133 _cleanup_(macsec_receive_channel_freep
) ReceiveChannel
*c
= NULL
;
139 assert(section_line
> 0);
141 r
= config_section_new(filename
, section_line
, &n
);
145 c
= ordered_hashmap_get(s
->receive_channels_by_section
, n
);
151 r
= macsec_receive_channel_new(s
, 0, &c
);
155 c
->section
= TAKE_PTR(n
);
157 r
= ordered_hashmap_ensure_put(&s
->receive_channels_by_section
, &config_section_hash_ops
, c
->section
, c
);
166 static TransmitAssociation
* macsec_transmit_association_free(TransmitAssociation
*a
) {
170 if (a
->macsec
&& a
->section
)
171 ordered_hashmap_remove(a
->macsec
->transmit_associations_by_section
, a
->section
);
173 config_section_free(a
->section
);
174 security_association_clear(&a
->sa
);
179 DEFINE_SECTION_CLEANUP_FUNCTIONS(TransmitAssociation
, macsec_transmit_association_free
);
181 static int macsec_transmit_association_new_static(MACsec
*s
, const char *filename
, unsigned section_line
, TransmitAssociation
**ret
) {
182 _cleanup_(config_section_freep
) ConfigSection
*n
= NULL
;
183 _cleanup_(macsec_transmit_association_freep
) TransmitAssociation
*a
= NULL
;
189 assert(section_line
> 0);
191 r
= config_section_new(filename
, section_line
, &n
);
195 a
= ordered_hashmap_get(s
->transmit_associations_by_section
, n
);
201 a
= new(TransmitAssociation
, 1);
205 *a
= (TransmitAssociation
) {
207 .section
= TAKE_PTR(n
),
210 security_association_init(&a
->sa
);
212 r
= ordered_hashmap_ensure_put(&s
->transmit_associations_by_section
, &config_section_hash_ops
, a
->section
, a
);
221 static int netdev_macsec_create_message(NetDev
*netdev
, int command
, sd_netlink_message
**ret
) {
222 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
226 assert(netdev
->ifindex
> 0);
228 r
= sd_genl_message_new(netdev
->manager
->genl
, MACSEC_GENL_NAME
, command
, &m
);
232 r
= sd_netlink_message_append_u32(m
, MACSEC_ATTR_IFINDEX
, netdev
->ifindex
);
241 static int netdev_macsec_fill_message_sci(NetDev
*netdev
, MACsecSCI
*sci
, sd_netlink_message
*m
) {
248 r
= sd_netlink_message_open_container(m
, MACSEC_ATTR_RXSC_CONFIG
);
252 r
= sd_netlink_message_append_u64(m
, MACSEC_RXSC_ATTR_SCI
, sci
->as_uint64
);
256 r
= sd_netlink_message_close_container(m
);
263 static int netdev_macsec_fill_message_sa(NetDev
*netdev
, SecurityAssociation
*a
, sd_netlink_message
*m
) {
270 r
= sd_netlink_message_open_container(m
, MACSEC_ATTR_SA_CONFIG
);
274 r
= sd_netlink_message_append_u8(m
, MACSEC_SA_ATTR_AN
, a
->association_number
);
278 if (a
->packet_number
> 0) {
279 r
= sd_netlink_message_append_u32(m
, MACSEC_SA_ATTR_PN
, a
->packet_number
);
284 if (a
->key_len
> 0) {
285 r
= sd_netlink_message_append_data(m
, MACSEC_SA_ATTR_KEYID
, a
->key_id
, MACSEC_KEYID_LEN
);
289 r
= sd_netlink_message_append_data(m
, MACSEC_SA_ATTR_KEY
, a
->key
, a
->key_len
);
294 if (a
->activate
>= 0) {
295 r
= sd_netlink_message_append_u8(m
, MACSEC_SA_ATTR_ACTIVE
, a
->activate
);
300 r
= sd_netlink_message_close_container(m
);
307 static int macsec_receive_association_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, NetDev
*netdev
) {
311 assert(netdev
->state
!= _NETDEV_STATE_INVALID
);
313 r
= sd_netlink_message_get_errno(m
);
315 log_netdev_info(netdev
,
316 "MACsec receive secure association exists, using it without changing parameters");
318 log_netdev_warning_errno(netdev
, r
,
319 "Failed to add receive secure association: %m");
320 netdev_enter_failed(netdev
);
325 log_netdev_debug(netdev
, "Receive secure association is configured");
330 static int netdev_macsec_configure_receive_association(NetDev
*netdev
, ReceiveAssociation
*a
) {
331 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
337 r
= netdev_macsec_create_message(netdev
, MACSEC_CMD_ADD_RXSA
, &m
);
339 return log_netdev_error_errno(netdev
, r
, "Failed to create netlink message: %m");
341 r
= netdev_macsec_fill_message_sa(netdev
, &a
->sa
, m
);
343 return log_netdev_error_errno(netdev
, r
, "Failed to fill netlink message: %m");
345 r
= netdev_macsec_fill_message_sci(netdev
, &a
->sci
, m
);
347 return log_netdev_error_errno(netdev
, r
, "Failed to fill netlink message: %m");
349 r
= netlink_call_async(netdev
->manager
->genl
, NULL
, m
, macsec_receive_association_handler
,
350 netdev_destroy_callback
, netdev
);
352 return log_netdev_error_errno(netdev
, r
, "Failed to configure receive secure association: %m");
359 static int macsec_receive_channel_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, ReceiveChannel
*c
) {
366 netdev
= NETDEV(c
->macsec
);
368 assert(netdev
->state
!= _NETDEV_STATE_INVALID
);
370 r
= sd_netlink_message_get_errno(m
);
372 log_netdev_debug(netdev
,
373 "MACsec receive channel exists, using it without changing parameters");
375 log_netdev_warning_errno(netdev
, r
,
376 "Failed to add receive secure channel: %m");
377 netdev_enter_failed(netdev
);
382 log_netdev_debug(netdev
, "Receive channel is configured");
384 for (unsigned i
= 0; i
< c
->n_rxsa
; i
++) {
385 r
= netdev_macsec_configure_receive_association(netdev
, c
->rxsa
[i
]);
387 log_netdev_warning_errno(netdev
, r
,
388 "Failed to configure receive security association: %m");
389 netdev_enter_failed(netdev
);
397 static void receive_channel_destroy_callback(ReceiveChannel
*c
) {
401 netdev_unref(NETDEV(c
->macsec
));
404 static int netdev_macsec_configure_receive_channel(NetDev
*netdev
, ReceiveChannel
*c
) {
405 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
411 r
= netdev_macsec_create_message(netdev
, MACSEC_CMD_ADD_RXSC
, &m
);
413 return log_netdev_error_errno(netdev
, r
, "Failed to create netlink message: %m");
415 r
= netdev_macsec_fill_message_sci(netdev
, &c
->sci
, m
);
417 return log_netdev_error_errno(netdev
, r
, "Failed to fill netlink message: %m");
419 r
= netlink_call_async(netdev
->manager
->genl
, NULL
, m
, macsec_receive_channel_handler
,
420 receive_channel_destroy_callback
, c
);
422 return log_netdev_error_errno(netdev
, r
, "Failed to configure receive channel: %m");
429 static int macsec_transmit_association_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, NetDev
*netdev
) {
433 assert(netdev
->state
!= _NETDEV_STATE_INVALID
);
435 r
= sd_netlink_message_get_errno(m
);
437 log_netdev_info(netdev
,
438 "MACsec transmit secure association exists, using it without changing parameters");
440 log_netdev_warning_errno(netdev
, r
,
441 "Failed to add transmit secure association: %m");
442 netdev_enter_failed(netdev
);
447 log_netdev_debug(netdev
, "Transmit secure association is configured");
452 static int netdev_macsec_configure_transmit_association(NetDev
*netdev
, TransmitAssociation
*a
) {
453 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
459 r
= netdev_macsec_create_message(netdev
, MACSEC_CMD_ADD_TXSA
, &m
);
461 return log_netdev_error_errno(netdev
, r
, "Failed to create netlink message: %m");
463 r
= netdev_macsec_fill_message_sa(netdev
, &a
->sa
, m
);
465 return log_netdev_error_errno(netdev
, r
, "Failed to fill netlink message: %m");
467 r
= netlink_call_async(netdev
->manager
->genl
, NULL
, m
, macsec_transmit_association_handler
,
468 netdev_destroy_callback
, netdev
);
470 return log_netdev_error_errno(netdev
, r
, "Failed to configure transmit secure association: %m");
477 static int netdev_macsec_configure(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
478 TransmitAssociation
*a
;
487 ORDERED_HASHMAP_FOREACH(a
, s
->transmit_associations_by_section
) {
488 r
= netdev_macsec_configure_transmit_association(netdev
, a
);
493 ORDERED_HASHMAP_FOREACH(c
, s
->receive_channels
) {
494 r
= netdev_macsec_configure_receive_channel(netdev
, c
);
502 static int netdev_macsec_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
514 r
= sd_netlink_message_append_u16(m
, IFLA_MACSEC_PORT
, v
->port
);
519 if (v
->encrypt
>= 0) {
520 r
= sd_netlink_message_append_u8(m
, IFLA_MACSEC_ENCRYPT
, v
->encrypt
);
525 r
= sd_netlink_message_append_u8(m
, IFLA_MACSEC_ENCODING_SA
, v
->encoding_an
);
532 int config_parse_macsec_port(
534 const char *filename
,
537 unsigned section_line
,
544 _cleanup_(macsec_receive_association_free_or_set_invalidp
) ReceiveAssociation
*b
= NULL
;
545 _cleanup_(macsec_receive_channel_free_or_set_invalidp
) ReceiveChannel
*c
= NULL
;
546 MACsec
*s
= userdata
;
557 /* This parses port used to make Secure Channel Identifier (SCI) */
559 if (streq(section
, "MACsec"))
561 else if (streq(section
, "MACsecReceiveChannel")) {
562 r
= macsec_receive_channel_new_static(s
, filename
, section_line
, &c
);
568 assert(streq(section
, "MACsecReceiveAssociation"));
570 r
= macsec_receive_association_new_static(s
, filename
, section_line
, &b
);
577 r
= parse_ip_port(rvalue
, &port
);
579 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
580 "Failed to parse port '%s' for secure channel identifier. Ignoring assignment: %m",
585 unaligned_write_be16(dest
, port
);
593 int config_parse_macsec_hw_address(
595 const char *filename
,
598 unsigned section_line
,
605 _cleanup_(macsec_receive_association_free_or_set_invalidp
) ReceiveAssociation
*b
= NULL
;
606 _cleanup_(macsec_receive_channel_free_or_set_invalidp
) ReceiveChannel
*c
= NULL
;
607 MACsec
*s
= userdata
;
616 if (streq(section
, "MACsecReceiveChannel"))
617 r
= macsec_receive_channel_new_static(s
, filename
, section_line
, &c
);
619 r
= macsec_receive_association_new_static(s
, filename
, section_line
, &b
);
623 r
= parse_ether_addr(rvalue
, b
? &b
->sci
.mac
: &c
->sci
.mac
);
625 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
626 "Failed to parse MAC address for secure channel identifier. "
627 "Ignoring assignment: %s", rvalue
);
637 int config_parse_macsec_packet_number(
639 const char *filename
,
642 unsigned section_line
,
649 _cleanup_(macsec_transmit_association_free_or_set_invalidp
) TransmitAssociation
*a
= NULL
;
650 _cleanup_(macsec_receive_association_free_or_set_invalidp
) ReceiveAssociation
*b
= NULL
;
651 MACsec
*s
= userdata
;
661 if (streq(section
, "MACsecTransmitAssociation"))
662 r
= macsec_transmit_association_new_static(s
, filename
, section_line
, &a
);
664 r
= macsec_receive_association_new_static(s
, filename
, section_line
, &b
);
668 dest
= a
? &a
->sa
.packet_number
: &b
->sa
.packet_number
;
670 r
= safe_atou32(rvalue
, &val
);
672 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
673 "Failed to parse packet number. Ignoring assignment: %s", rvalue
);
676 if (streq(section
, "MACsecTransmitAssociation") && val
== 0) {
677 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
678 "Invalid packet number. Ignoring assignment: %s", rvalue
);
689 int config_parse_macsec_key(
691 const char *filename
,
694 unsigned section_line
,
701 _cleanup_(macsec_transmit_association_free_or_set_invalidp
) TransmitAssociation
*a
= NULL
;
702 _cleanup_(macsec_receive_association_free_or_set_invalidp
) ReceiveAssociation
*b
= NULL
;
703 _cleanup_(erase_and_freep
) void *p
= NULL
;
704 MACsec
*s
= userdata
;
705 SecurityAssociation
*dest
;
715 (void) warn_file_is_world_accessible(filename
, NULL
, unit
, line
);
717 if (streq(section
, "MACsecTransmitAssociation"))
718 r
= macsec_transmit_association_new_static(s
, filename
, section_line
, &a
);
720 r
= macsec_receive_association_new_static(s
, filename
, section_line
, &b
);
724 dest
= a
? &a
->sa
: &b
->sa
;
726 r
= unhexmem_full(rvalue
, strlen(rvalue
), true, &p
, &l
);
728 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse key. Ignoring assignment: %m");
733 /* See DEFAULT_SAK_LEN in drivers/net/macsec.c */
734 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Invalid key length (%zu). Ignoring assignment", l
);
738 explicit_bzero_safe(dest
->key
, dest
->key_len
);
739 free_and_replace(dest
->key
, p
);
748 int config_parse_macsec_key_file(
750 const char *filename
,
753 unsigned section_line
,
760 _cleanup_(macsec_transmit_association_free_or_set_invalidp
) TransmitAssociation
*a
= NULL
;
761 _cleanup_(macsec_receive_association_free_or_set_invalidp
) ReceiveAssociation
*b
= NULL
;
762 _cleanup_free_
char *path
= NULL
;
763 MACsec
*s
= userdata
;
773 if (streq(section
, "MACsecTransmitAssociation"))
774 r
= macsec_transmit_association_new_static(s
, filename
, section_line
, &a
);
776 r
= macsec_receive_association_new_static(s
, filename
, section_line
, &b
);
780 dest
= a
? &a
->sa
.key_file
: &b
->sa
.key_file
;
782 if (isempty(rvalue
)) {
783 *dest
= mfree(*dest
);
787 path
= strdup(rvalue
);
791 if (path_simplify_and_warn(path
, PATH_CHECK_ABSOLUTE
, unit
, filename
, line
, lvalue
) < 0)
794 free_and_replace(*dest
, path
);
801 int config_parse_macsec_key_id(
803 const char *filename
,
806 unsigned section_line
,
813 _cleanup_(macsec_transmit_association_free_or_set_invalidp
) TransmitAssociation
*a
= NULL
;
814 _cleanup_(macsec_receive_association_free_or_set_invalidp
) ReceiveAssociation
*b
= NULL
;
815 _cleanup_free_
void *p
= NULL
;
816 MACsec
*s
= userdata
;
827 if (streq(section
, "MACsecTransmitAssociation"))
828 r
= macsec_transmit_association_new_static(s
, filename
, section_line
, &a
);
830 r
= macsec_receive_association_new_static(s
, filename
, section_line
, &b
);
834 r
= unhexmem(rvalue
, strlen(rvalue
), &p
, &l
);
838 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
839 "Failed to parse KeyId=%s, ignoring assignment: %m", rvalue
);
842 if (l
> MACSEC_KEYID_LEN
) {
843 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
844 "Specified KeyId= is larger then the allowed maximum (%zu > %u), ignoring: %s",
845 l
, MACSEC_KEYID_LEN
, rvalue
);
849 dest
= a
? a
->sa
.key_id
: b
->sa
.key_id
;
850 memcpy_safe(dest
, p
, l
);
851 memzero(dest
+ l
, MACSEC_KEYID_LEN
- l
);
859 int config_parse_macsec_sa_activate(
861 const char *filename
,
864 unsigned section_line
,
871 _cleanup_(macsec_transmit_association_free_or_set_invalidp
) TransmitAssociation
*a
= NULL
;
872 _cleanup_(macsec_receive_association_free_or_set_invalidp
) ReceiveAssociation
*b
= NULL
;
873 MACsec
*s
= userdata
;
883 if (streq(section
, "MACsecTransmitAssociation"))
884 r
= macsec_transmit_association_new_static(s
, filename
, section_line
, &a
);
886 r
= macsec_receive_association_new_static(s
, filename
, section_line
, &b
);
890 dest
= a
? &a
->sa
.activate
: &b
->sa
.activate
;
895 r
= parse_boolean(rvalue
);
897 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
898 "Failed to parse activation mode of %s security association. "
899 "Ignoring assignment: %s",
900 streq(section
, "MACsecTransmitAssociation") ? "transmit" : "receive",
913 int config_parse_macsec_use_for_encoding(
915 const char *filename
,
918 unsigned section_line
,
925 _cleanup_(macsec_transmit_association_free_or_set_invalidp
) TransmitAssociation
*a
= NULL
;
926 MACsec
*s
= userdata
;
935 r
= macsec_transmit_association_new_static(s
, filename
, section_line
, &a
);
939 if (isempty(rvalue
)) {
940 a
->sa
.use_for_encoding
= -1;
945 r
= parse_boolean(rvalue
);
947 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
948 "Failed to parse %s= setting. Ignoring assignment: %s",
953 a
->sa
.use_for_encoding
= r
;
954 if (a
->sa
.use_for_encoding
> 0)
955 a
->sa
.activate
= true;
962 static int macsec_read_key_file(NetDev
*netdev
, SecurityAssociation
*sa
) {
963 _cleanup_(erase_and_freep
) uint8_t *key
= NULL
;
973 (void) warn_file_is_world_accessible(sa
->key_file
, NULL
, NULL
, 0);
975 r
= read_full_file_full(
976 AT_FDCWD
, sa
->key_file
, UINT64_MAX
, SIZE_MAX
,
977 READ_FULL_FILE_SECURE
| READ_FULL_FILE_UNHEX
| READ_FULL_FILE_WARN_WORLD_READABLE
| READ_FULL_FILE_CONNECT_SOCKET
,
978 NULL
, (char **) &key
, &key_len
);
980 return log_netdev_error_errno(netdev
, r
,
981 "Failed to read key from '%s', ignoring: %m",
985 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
986 "Invalid key length (%zu bytes), ignoring: %m", key_len
);
988 explicit_bzero_safe(sa
->key
, sa
->key_len
);
989 free_and_replace(sa
->key
, key
);
990 sa
->key_len
= key_len
;
995 static int macsec_receive_channel_verify(ReceiveChannel
*c
) {
1002 netdev
= NETDEV(c
->macsec
);
1004 if (section_is_invalid(c
->section
))
1007 if (ether_addr_is_null(&c
->sci
.mac
))
1008 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
1009 "%s: MACsec receive channel without MAC address configured. "
1010 "Ignoring [MACsecReceiveChannel] section from line %u",
1011 c
->section
->filename
, c
->section
->line
);
1013 if (c
->sci
.port
== 0)
1014 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
1015 "%s: MACsec receive channel without port configured. "
1016 "Ignoring [MACsecReceiveChannel] section from line %u",
1017 c
->section
->filename
, c
->section
->line
);
1019 r
= ordered_hashmap_ensure_put(&c
->macsec
->receive_channels
, &uint64_hash_ops
, &c
->sci
.as_uint64
, c
);
1023 return log_netdev_error_errno(netdev
, r
,
1024 "%s: Multiple [MACsecReceiveChannel] sections have same SCI, "
1025 "Ignoring [MACsecReceiveChannel] section from line %u",
1026 c
->section
->filename
, c
->section
->line
);
1028 return log_netdev_error_errno(netdev
, r
,
1029 "%s: Failed to store [MACsecReceiveChannel] section at hashmap, "
1030 "Ignoring [MACsecReceiveChannel] section from line %u",
1031 c
->section
->filename
, c
->section
->line
);
1035 static int macsec_transmit_association_verify(TransmitAssociation
*t
) {
1042 netdev
= NETDEV(t
->macsec
);
1044 if (section_is_invalid(t
->section
))
1047 if (t
->sa
.packet_number
== 0)
1048 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
1049 "%s: MACsec transmit secure association without PacketNumber= configured. "
1050 "Ignoring [MACsecTransmitAssociation] section from line %u",
1051 t
->section
->filename
, t
->section
->line
);
1053 r
= macsec_read_key_file(netdev
, &t
->sa
);
1057 if (t
->sa
.key_len
<= 0)
1058 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
1059 "%s: MACsec transmit secure association without key configured. "
1060 "Ignoring [MACsecTransmitAssociation] section from line %u",
1061 t
->section
->filename
, t
->section
->line
);
1066 static int macsec_receive_association_verify(ReceiveAssociation
*a
) {
1074 netdev
= NETDEV(a
->macsec
);
1076 if (section_is_invalid(a
->section
))
1079 r
= macsec_read_key_file(netdev
, &a
->sa
);
1083 if (a
->sa
.key_len
<= 0)
1084 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
1085 "%s: MACsec receive secure association without key configured. "
1086 "Ignoring [MACsecReceiveAssociation] section from line %u",
1087 a
->section
->filename
, a
->section
->line
);
1089 if (ether_addr_is_null(&a
->sci
.mac
))
1090 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
1091 "%s: MACsec receive secure association without MAC address configured. "
1092 "Ignoring [MACsecReceiveAssociation] section from line %u",
1093 a
->section
->filename
, a
->section
->line
);
1095 if (a
->sci
.port
== 0)
1096 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
1097 "%s: MACsec receive secure association without port configured. "
1098 "Ignoring [MACsecReceiveAssociation] section from line %u",
1099 a
->section
->filename
, a
->section
->line
);
1101 c
= ordered_hashmap_get(a
->macsec
->receive_channels
, &a
->sci
.as_uint64
);
1103 _cleanup_(macsec_receive_channel_freep
) ReceiveChannel
*new_channel
= NULL
;
1105 r
= macsec_receive_channel_new(a
->macsec
, a
->sci
.as_uint64
, &new_channel
);
1109 r
= ordered_hashmap_ensure_put(&a
->macsec
->receive_channels
, &uint64_hash_ops
, &new_channel
->sci
.as_uint64
, new_channel
);
1113 return log_netdev_error_errno(netdev
, r
,
1114 "%s: Failed to store receive channel at hashmap, "
1115 "Ignoring [MACsecReceiveAssociation] section from line %u",
1116 a
->section
->filename
, a
->section
->line
);
1117 c
= TAKE_PTR(new_channel
);
1119 if (c
->n_rxsa
>= MACSEC_MAX_ASSOCIATION_NUMBER
)
1120 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(ERANGE
),
1121 "%s: Too many [MACsecReceiveAssociation] sections for the same receive channel, "
1122 "Ignoring [MACsecReceiveAssociation] section from line %u",
1123 a
->section
->filename
, a
->section
->line
);
1125 a
->sa
.association_number
= c
->n_rxsa
;
1126 c
->rxsa
[c
->n_rxsa
++] = a
;
1131 static int netdev_macsec_verify(NetDev
*netdev
, const char *filename
) {
1132 MACsec
*v
= MACSEC(netdev
);
1133 TransmitAssociation
*a
;
1134 ReceiveAssociation
*n
;
1136 uint8_t an
, encoding_an
;
1137 bool use_for_encoding
;
1144 ORDERED_HASHMAP_FOREACH(c
, v
->receive_channels_by_section
) {
1145 r
= macsec_receive_channel_verify(c
);
1147 macsec_receive_channel_free(c
);
1151 use_for_encoding
= false;
1153 ORDERED_HASHMAP_FOREACH(a
, v
->transmit_associations_by_section
) {
1154 r
= macsec_transmit_association_verify(a
);
1156 macsec_transmit_association_free(a
);
1160 if (an
>= MACSEC_MAX_ASSOCIATION_NUMBER
) {
1161 log_netdev_error(netdev
,
1162 "%s: Too many [MACsecTransmitAssociation] sections configured. "
1163 "Ignoring [MACsecTransmitAssociation] section from line %u",
1164 a
->section
->filename
, a
->section
->line
);
1165 macsec_transmit_association_free(a
);
1169 a
->sa
.association_number
= an
++;
1171 if (a
->sa
.use_for_encoding
> 0) {
1172 if (use_for_encoding
) {
1173 log_netdev_warning(netdev
,
1174 "%s: Multiple security associations are set to be used for transmit channel."
1175 "Disabling UseForEncoding= in [MACsecTransmitAssociation] section from line %u",
1176 a
->section
->filename
, a
->section
->line
);
1177 a
->sa
.use_for_encoding
= false;
1179 encoding_an
= a
->sa
.association_number
;
1180 use_for_encoding
= true;
1185 assert(encoding_an
< MACSEC_MAX_ASSOCIATION_NUMBER
);
1186 v
->encoding_an
= encoding_an
;
1188 ORDERED_HASHMAP_FOREACH(n
, v
->receive_associations_by_section
) {
1189 r
= macsec_receive_association_verify(n
);
1191 macsec_receive_association_free(n
);
1197 static void macsec_init(NetDev
*netdev
) {
1209 static void macsec_done(NetDev
*netdev
) {
1218 ordered_hashmap_free_with_destructor(t
->receive_channels
, macsec_receive_channel_free
);
1219 ordered_hashmap_free_with_destructor(t
->receive_channels_by_section
, macsec_receive_channel_free
);
1220 ordered_hashmap_free_with_destructor(t
->transmit_associations_by_section
, macsec_transmit_association_free
);
1221 ordered_hashmap_free_with_destructor(t
->receive_associations_by_section
, macsec_receive_association_free
);
1224 const NetDevVTable macsec_vtable
= {
1225 .object_size
= sizeof(MACsec
),
1226 .init
= macsec_init
,
1227 .sections
= NETDEV_COMMON_SECTIONS
"MACsec\0MACsecReceiveChannel\0MACsecTransmitAssociation\0MACsecReceiveAssociation\0",
1228 .fill_message_create
= netdev_macsec_fill_message_create
,
1229 .post_create
= netdev_macsec_configure
,
1230 .done
= macsec_done
,
1231 .create_type
= NETDEV_CREATE_STACKED
,
1232 .config_verify
= netdev_macsec_verify
,
1233 .iftype
= ARPHRD_ETHER
,
1234 .generate_mac
= true,