1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include <netinet/in.h>
4 #include <linux/if_ether.h>
5 #include <linux/if_macsec.h>
6 #include <linux/genetlink.h>
8 #include "conf-parser.h"
11 #include "hexdecoct.h"
13 #include "memory-util.h"
14 #include "netlink-util.h"
15 #include "network-internal.h"
16 #include "networkd-address.h"
17 #include "networkd-manager.h"
18 #include "path-util.h"
19 #include "socket-util.h"
20 #include "string-table.h"
21 #include "string-util.h"
24 static void security_association_clear(SecurityAssociation
*sa
) {
28 explicit_bzero_safe(sa
->key
, sa
->key_len
);
33 static void security_association_init(SecurityAssociation
*sa
) {
37 sa
->use_for_encoding
= -1;
40 static void macsec_receive_association_free(ReceiveAssociation
*c
) {
44 if (c
->macsec
&& c
->section
)
45 ordered_hashmap_remove(c
->macsec
->receive_associations_by_section
, c
->section
);
47 network_config_section_free(c
->section
);
48 security_association_clear(&c
->sa
);
53 DEFINE_NETWORK_SECTION_FUNCTIONS(ReceiveAssociation
, macsec_receive_association_free
);
55 static int macsec_receive_association_new_static(MACsec
*s
, const char *filename
, unsigned section_line
, ReceiveAssociation
**ret
) {
56 _cleanup_(network_config_section_freep
) NetworkConfigSection
*n
= NULL
;
57 _cleanup_(macsec_receive_association_freep
) ReceiveAssociation
*c
= NULL
;
63 assert(section_line
> 0);
65 r
= network_config_section_new(filename
, section_line
, &n
);
69 c
= ordered_hashmap_get(s
->receive_associations_by_section
, n
);
75 c
= new(ReceiveAssociation
, 1);
79 *c
= (ReceiveAssociation
) {
81 .section
= TAKE_PTR(n
),
84 security_association_init(&c
->sa
);
86 r
= ordered_hashmap_ensure_allocated(&s
->receive_associations_by_section
, &network_config_hash_ops
);
90 r
= ordered_hashmap_put(s
->receive_associations_by_section
, c
->section
, c
);
99 static void macsec_receive_channel_free(ReceiveChannel
*c
) {
104 if (c
->sci
.as_uint64
> 0)
105 ordered_hashmap_remove_value(c
->macsec
->receive_channels
, &c
->sci
.as_uint64
, c
);
108 ordered_hashmap_remove(c
->macsec
->receive_channels_by_section
, c
->section
);
111 network_config_section_free(c
->section
);
116 DEFINE_NETWORK_SECTION_FUNCTIONS(ReceiveChannel
, macsec_receive_channel_free
);
118 static int macsec_receive_channel_new(MACsec
*s
, uint64_t sci
, ReceiveChannel
**ret
) {
123 c
= new(ReceiveChannel
, 1);
127 *c
= (ReceiveChannel
) {
129 .sci
.as_uint64
= sci
,
136 static int macsec_receive_channel_new_static(MACsec
*s
, const char *filename
, unsigned section_line
, ReceiveChannel
**ret
) {
137 _cleanup_(network_config_section_freep
) NetworkConfigSection
*n
= NULL
;
138 _cleanup_(macsec_receive_channel_freep
) ReceiveChannel
*c
= NULL
;
144 assert(section_line
> 0);
146 r
= network_config_section_new(filename
, section_line
, &n
);
150 c
= ordered_hashmap_get(s
->receive_channels_by_section
, n
);
156 r
= macsec_receive_channel_new(s
, 0, &c
);
160 c
->section
= TAKE_PTR(n
);
162 r
= ordered_hashmap_ensure_allocated(&s
->receive_channels_by_section
, &network_config_hash_ops
);
166 r
= ordered_hashmap_put(s
->receive_channels_by_section
, c
->section
, c
);
175 static void macsec_transmit_association_free(TransmitAssociation
*a
) {
179 if (a
->macsec
&& a
->section
)
180 ordered_hashmap_remove(a
->macsec
->transmit_associations_by_section
, a
->section
);
182 network_config_section_free(a
->section
);
183 security_association_clear(&a
->sa
);
188 DEFINE_NETWORK_SECTION_FUNCTIONS(TransmitAssociation
, macsec_transmit_association_free
);
190 static int macsec_transmit_association_new_static(MACsec
*s
, const char *filename
, unsigned section_line
, TransmitAssociation
**ret
) {
191 _cleanup_(network_config_section_freep
) NetworkConfigSection
*n
= NULL
;
192 _cleanup_(macsec_transmit_association_freep
) TransmitAssociation
*a
= NULL
;
198 assert(section_line
> 0);
200 r
= network_config_section_new(filename
, section_line
, &n
);
204 a
= ordered_hashmap_get(s
->transmit_associations_by_section
, n
);
210 a
= new(TransmitAssociation
, 1);
214 *a
= (TransmitAssociation
) {
216 .section
= TAKE_PTR(n
),
219 security_association_init(&a
->sa
);
221 r
= ordered_hashmap_ensure_allocated(&s
->transmit_associations_by_section
, &network_config_hash_ops
);
225 r
= ordered_hashmap_put(s
->transmit_associations_by_section
, a
->section
, a
);
234 static int netdev_macsec_fill_message(NetDev
*netdev
, int command
, sd_netlink_message
**ret
) {
235 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
239 assert(netdev
->ifindex
> 0);
241 r
= sd_genl_message_new(netdev
->manager
->genl
, SD_GENL_MACSEC
, command
, &m
);
243 return log_netdev_error_errno(netdev
, r
, "Failed to create generic netlink message: %m");
245 r
= sd_netlink_message_append_u32(m
, MACSEC_ATTR_IFINDEX
, netdev
->ifindex
);
247 return log_netdev_error_errno(netdev
, r
, "Could not append MACSEC_ATTR_IFINDEX attribute: %m");
254 static int netdev_macsec_fill_message_sci(NetDev
*netdev
, MACsecSCI
*sci
, sd_netlink_message
*m
) {
261 r
= sd_netlink_message_open_container(m
, MACSEC_ATTR_RXSC_CONFIG
);
263 return log_netdev_error_errno(netdev
, r
, "Could not append MACSEC_ATTR_RXSC_CONFIG attribute: %m");
265 r
= sd_netlink_message_append_u64(m
, MACSEC_RXSC_ATTR_SCI
, sci
->as_uint64
);
267 return log_netdev_error_errno(netdev
, r
, "Could not append MACSEC_RXSC_ATTR_SCI attribute: %m");
269 r
= sd_netlink_message_close_container(m
);
271 return log_netdev_error_errno(netdev
, r
, "Could not append MACSEC_ATTR_RXSC_CONFIG attribute: %m");
276 static int netdev_macsec_fill_message_sa(NetDev
*netdev
, SecurityAssociation
*a
, sd_netlink_message
*m
) {
283 r
= sd_netlink_message_open_container(m
, MACSEC_ATTR_SA_CONFIG
);
285 return log_netdev_error_errno(netdev
, r
, "Could not append MACSEC_ATTR_SA_CONFIG attribute: %m");
287 r
= sd_netlink_message_append_u8(m
, MACSEC_SA_ATTR_AN
, a
->association_number
);
289 return log_netdev_error_errno(netdev
, r
, "Could not append MACSEC_SA_ATTR_AN attribute: %m");
291 if (a
->packet_number
> 0) {
292 r
= sd_netlink_message_append_u32(m
, MACSEC_SA_ATTR_PN
, a
->packet_number
);
294 return log_netdev_error_errno(netdev
, r
, "Could not append MACSEC_SA_ATTR_PN attribute: %m");
297 if (a
->key_len
> 0) {
298 r
= sd_netlink_message_append_data(m
, MACSEC_SA_ATTR_KEYID
, a
->key_id
, MACSEC_KEYID_LEN
);
300 return log_netdev_error_errno(netdev
, r
, "Could not append MACSEC_SA_ATTR_KEYID attribute: %m");
302 r
= sd_netlink_message_append_data(m
, MACSEC_SA_ATTR_KEY
, a
->key
, a
->key_len
);
304 return log_netdev_error_errno(netdev
, r
, "Could not append MACSEC_SA_ATTR_KEY attribute: %m");
307 if (a
->activate
>= 0) {
308 r
= sd_netlink_message_append_u8(m
, MACSEC_SA_ATTR_ACTIVE
, a
->activate
);
310 return log_netdev_error_errno(netdev
, r
, "Could not append MACSEC_SA_ATTR_ACTIVE attribute: %m");
313 r
= sd_netlink_message_close_container(m
);
315 return log_netdev_error_errno(netdev
, r
, "Could not append MACSEC_ATTR_SA_CONFIG attribute: %m");
320 static int macsec_receive_association_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, NetDev
*netdev
) {
324 assert(netdev
->state
!= _NETDEV_STATE_INVALID
);
326 r
= sd_netlink_message_get_errno(m
);
328 log_netdev_info(netdev
,
329 "MACsec receive secure association exists, "
330 "using existing without changing its parameters");
332 log_netdev_warning_errno(netdev
, r
,
333 "Failed to add receive secure association: %m");
339 log_netdev_debug(netdev
, "Receive secure association is configured");
344 static int netdev_macsec_configure_receive_association(NetDev
*netdev
, ReceiveAssociation
*a
) {
345 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
351 r
= netdev_macsec_fill_message(netdev
, MACSEC_CMD_ADD_RXSA
, &m
);
355 r
= netdev_macsec_fill_message_sa(netdev
, &a
->sa
, m
);
359 r
= netdev_macsec_fill_message_sci(netdev
, &a
->sci
, m
);
363 r
= netlink_call_async(netdev
->manager
->genl
, NULL
, m
, macsec_receive_association_handler
,
364 netdev_destroy_callback
, netdev
);
366 return log_netdev_error_errno(netdev
, r
, "Failed to configure receive secure association: %m");
373 static int macsec_receive_channel_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, ReceiveChannel
*c
) {
381 netdev
= NETDEV(c
->macsec
);
383 assert(netdev
->state
!= _NETDEV_STATE_INVALID
);
385 r
= sd_netlink_message_get_errno(m
);
387 log_netdev_debug(netdev
,
388 "MACsec receive channel exists, "
389 "using existing without changing its parameters");
391 log_netdev_warning_errno(netdev
, r
,
392 "Failed to add receive secure channel: %m");
398 log_netdev_debug(netdev
, "Receive channel is configured");
400 for (i
= 0; i
< c
->n_rxsa
; i
++) {
401 r
= netdev_macsec_configure_receive_association(netdev
, c
->rxsa
[i
]);
403 log_netdev_warning_errno(netdev
, r
,
404 "Failed to configure receive security association: %m");
413 static void receive_channel_destroy_callback(ReceiveChannel
*c
) {
417 netdev_unref(NETDEV(c
->macsec
));
420 static int netdev_macsec_configure_receive_channel(NetDev
*netdev
, ReceiveChannel
*c
) {
421 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
427 r
= netdev_macsec_fill_message(netdev
, MACSEC_CMD_ADD_RXSC
, &m
);
431 r
= netdev_macsec_fill_message_sci(netdev
, &c
->sci
, m
);
435 r
= netlink_call_async(netdev
->manager
->genl
, NULL
, m
, macsec_receive_channel_handler
,
436 receive_channel_destroy_callback
, c
);
438 return log_netdev_error_errno(netdev
, r
, "Failed to configure receive channel: %m");
445 static int macsec_transmit_association_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, NetDev
*netdev
) {
449 assert(netdev
->state
!= _NETDEV_STATE_INVALID
);
451 r
= sd_netlink_message_get_errno(m
);
453 log_netdev_info(netdev
,
454 "MACsec transmit secure association exists, "
455 "using existing without changing its parameters");
457 log_netdev_warning_errno(netdev
, r
,
458 "Failed to add transmit secure association: %m");
464 log_netdev_debug(netdev
, "Transmit secure association is configured");
469 static int netdev_macsec_configure_transmit_association(NetDev
*netdev
, TransmitAssociation
*a
) {
470 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
476 r
= netdev_macsec_fill_message(netdev
, MACSEC_CMD_ADD_TXSA
, &m
);
480 r
= netdev_macsec_fill_message_sa(netdev
, &a
->sa
, m
);
484 r
= netlink_call_async(netdev
->manager
->genl
, NULL
, m
, macsec_transmit_association_handler
,
485 netdev_destroy_callback
, netdev
);
487 return log_netdev_error_errno(netdev
, r
, "Failed to configure transmit secure association: %m");
494 static int netdev_macsec_configure(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
495 TransmitAssociation
*a
;
505 ORDERED_HASHMAP_FOREACH(a
, s
->transmit_associations_by_section
, i
) {
506 r
= netdev_macsec_configure_transmit_association(netdev
, a
);
511 ORDERED_HASHMAP_FOREACH(c
, s
->receive_channels
, i
) {
512 r
= netdev_macsec_configure_receive_channel(netdev
, c
);
520 static int netdev_macsec_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
530 r
= sd_netlink_message_append_u16(m
, IFLA_MACSEC_PORT
, v
->port
);
532 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_MACSEC_PORT attribute: %m");
535 if (v
->encrypt
>= 0) {
536 r
= sd_netlink_message_append_u8(m
, IFLA_MACSEC_ENCRYPT
, v
->encrypt
);
538 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_MACSEC_ENCRYPT attribute: %m");
541 r
= sd_netlink_message_append_u8(m
, IFLA_MACSEC_ENCODING_SA
, v
->encoding_an
);
543 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_MACSEC_ENCODING_SA attribute: %m");
548 int config_parse_macsec_port(
550 const char *filename
,
553 unsigned section_line
,
560 _cleanup_(macsec_receive_association_free_or_set_invalidp
) ReceiveAssociation
*b
= NULL
;
561 _cleanup_(macsec_receive_channel_free_or_set_invalidp
) ReceiveChannel
*c
= NULL
;
562 MACsec
*s
= userdata
;
573 /* This parses port used to make Secure Channel Identifier (SCI) */
575 if (streq(section
, "MACsec"))
577 else if (streq(section
, "MACsecReceiveChannel")) {
578 r
= macsec_receive_channel_new_static(s
, filename
, section_line
, &c
);
584 assert(streq(section
, "MACsecReceiveAssociation"));
586 r
= macsec_receive_association_new_static(s
, filename
, section_line
, &b
);
593 r
= parse_ip_port(rvalue
, &port
);
595 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
596 "Failed to parse port '%s' for secure channel identifier. Ignoring assignment: %m",
601 unaligned_write_be16(dest
, port
);
609 int config_parse_macsec_hw_address(
611 const char *filename
,
614 unsigned section_line
,
621 _cleanup_(macsec_receive_association_free_or_set_invalidp
) ReceiveAssociation
*b
= NULL
;
622 _cleanup_(macsec_receive_channel_free_or_set_invalidp
) ReceiveChannel
*c
= NULL
;
623 MACsec
*s
= userdata
;
632 if (streq(section
, "MACsecReceiveChannel"))
633 r
= macsec_receive_channel_new_static(s
, filename
, section_line
, &c
);
635 r
= macsec_receive_association_new_static(s
, filename
, section_line
, &b
);
639 r
= ether_addr_from_string(rvalue
, b
? &b
->sci
.mac
: &c
->sci
.mac
);
641 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
642 "Failed to parse MAC address for secure channel identifier. "
643 "Ignoring assignment: %s", rvalue
);
653 int config_parse_macsec_packet_number(
655 const char *filename
,
658 unsigned section_line
,
665 _cleanup_(macsec_transmit_association_free_or_set_invalidp
) TransmitAssociation
*a
= NULL
;
666 _cleanup_(macsec_receive_association_free_or_set_invalidp
) ReceiveAssociation
*b
= NULL
;
667 MACsec
*s
= userdata
;
677 if (streq(section
, "MACsecTransmitAssociation"))
678 r
= macsec_transmit_association_new_static(s
, filename
, section_line
, &a
);
680 r
= macsec_receive_association_new_static(s
, filename
, section_line
, &b
);
684 dest
= a
? &a
->sa
.packet_number
: &b
->sa
.packet_number
;
686 r
= safe_atou32(rvalue
, &val
);
688 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
689 "Failed to parse packet number. Ignoring assignment: %s", rvalue
);
692 if (streq(section
, "MACsecTransmitAssociation") && val
== 0) {
693 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
694 "Invalid packet number. Ignoring assignment: %s", rvalue
);
705 int config_parse_macsec_key(
707 const char *filename
,
710 unsigned section_line
,
717 _cleanup_(macsec_transmit_association_free_or_set_invalidp
) TransmitAssociation
*a
= NULL
;
718 _cleanup_(macsec_receive_association_free_or_set_invalidp
) ReceiveAssociation
*b
= NULL
;
719 _cleanup_(erase_and_freep
) void *p
= NULL
;
720 MACsec
*s
= userdata
;
721 SecurityAssociation
*dest
;
731 (void) warn_file_is_world_accessible(filename
, NULL
, unit
, line
);
733 if (streq(section
, "MACsecTransmitAssociation"))
734 r
= macsec_transmit_association_new_static(s
, filename
, section_line
, &a
);
736 r
= macsec_receive_association_new_static(s
, filename
, section_line
, &b
);
740 dest
= a
? &a
->sa
: &b
->sa
;
742 r
= unhexmem_full(rvalue
, strlen(rvalue
), true, &p
, &l
);
744 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse key. Ignoring assignment: %m");
749 /* See DEFAULT_SAK_LEN in drivers/net/macsec.c */
750 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Invalid key length (%zu). Ignoring assignment", l
);
754 explicit_bzero_safe(dest
->key
, dest
->key_len
);
755 free_and_replace(dest
->key
, p
);
764 int config_parse_macsec_key_file(
766 const char *filename
,
769 unsigned section_line
,
776 _cleanup_(macsec_transmit_association_free_or_set_invalidp
) TransmitAssociation
*a
= NULL
;
777 _cleanup_(macsec_receive_association_free_or_set_invalidp
) ReceiveAssociation
*b
= NULL
;
778 _cleanup_free_
char *path
= NULL
;
779 MACsec
*s
= userdata
;
789 if (streq(section
, "MACsecTransmitAssociation"))
790 r
= macsec_transmit_association_new_static(s
, filename
, section_line
, &a
);
792 r
= macsec_receive_association_new_static(s
, filename
, section_line
, &b
);
796 dest
= a
? &a
->sa
.key_file
: &b
->sa
.key_file
;
798 if (isempty(rvalue
)) {
799 *dest
= mfree(*dest
);
803 path
= strdup(rvalue
);
807 if (path_simplify_and_warn(path
, PATH_CHECK_ABSOLUTE
, unit
, filename
, line
, lvalue
) < 0)
810 free_and_replace(*dest
, path
);
817 int config_parse_macsec_key_id(
819 const char *filename
,
822 unsigned section_line
,
829 _cleanup_(macsec_transmit_association_free_or_set_invalidp
) TransmitAssociation
*a
= NULL
;
830 _cleanup_(macsec_receive_association_free_or_set_invalidp
) ReceiveAssociation
*b
= NULL
;
831 _cleanup_free_
void *p
= NULL
;
832 MACsec
*s
= userdata
;
843 if (streq(section
, "MACsecTransmitAssociation"))
844 r
= macsec_transmit_association_new_static(s
, filename
, section_line
, &a
);
846 r
= macsec_receive_association_new_static(s
, filename
, section_line
, &b
);
850 r
= unhexmem(rvalue
, strlen(rvalue
), &p
, &l
);
852 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse KeyId \"%s\": %m", rvalue
);
855 if (l
> MACSEC_KEYID_LEN
)
856 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
857 "Specified KeyId is larger then the allowed maximum (%zu > %u), ignoring: %s",
858 l
, MACSEC_KEYID_LEN
, rvalue
);
860 dest
= a
? a
->sa
.key_id
: b
->sa
.key_id
;
861 memcpy_safe(dest
, p
, l
);
862 memzero(dest
+ l
, MACSEC_KEYID_LEN
- l
);
870 int config_parse_macsec_sa_activate(
872 const char *filename
,
875 unsigned section_line
,
882 _cleanup_(macsec_transmit_association_free_or_set_invalidp
) TransmitAssociation
*a
= NULL
;
883 _cleanup_(macsec_receive_association_free_or_set_invalidp
) ReceiveAssociation
*b
= NULL
;
884 MACsec
*s
= userdata
;
894 if (streq(section
, "MACsecTransmitAssociation"))
895 r
= macsec_transmit_association_new_static(s
, filename
, section_line
, &a
);
897 r
= macsec_receive_association_new_static(s
, filename
, section_line
, &b
);
901 dest
= a
? &a
->sa
.activate
: &b
->sa
.activate
;
906 r
= parse_boolean(rvalue
);
908 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
909 "Failed to parse activation mode of %s security association. "
910 "Ignoring assignment: %s",
911 streq(section
, "MACsecTransmitAssociation") ? "transmit" : "receive",
924 int config_parse_macsec_use_for_encoding(
926 const char *filename
,
929 unsigned section_line
,
936 _cleanup_(macsec_transmit_association_free_or_set_invalidp
) TransmitAssociation
*a
= NULL
;
937 MACsec
*s
= userdata
;
946 r
= macsec_transmit_association_new_static(s
, filename
, section_line
, &a
);
950 if (isempty(rvalue
)) {
951 a
->sa
.use_for_encoding
= -1;
956 r
= parse_boolean(rvalue
);
958 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
959 "Failed to parse %s= setting. Ignoring assignment: %s",
964 a
->sa
.use_for_encoding
= r
;
965 if (a
->sa
.use_for_encoding
> 0)
966 a
->sa
.activate
= true;
973 static int macsec_read_key_file(NetDev
*netdev
, SecurityAssociation
*sa
) {
974 _cleanup_(erase_and_freep
) uint8_t *key
= NULL
;
984 (void) warn_file_is_world_accessible(sa
->key_file
, NULL
, NULL
, 0);
986 r
= read_full_file_full(AT_FDCWD
, sa
->key_file
, READ_FULL_FILE_SECURE
| READ_FULL_FILE_UNHEX
, (char **) &key
, &key_len
);
988 return log_netdev_error_errno(netdev
, r
,
989 "Failed to read key from '%s', ignoring: %m",
993 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
994 "Invalid key length (%zu bytes), ignoring: %m", key_len
);
996 explicit_bzero_safe(sa
->key
, sa
->key_len
);
997 free_and_replace(sa
->key
, key
);
998 sa
->key_len
= key_len
;
1003 static int macsec_receive_channel_verify(ReceiveChannel
*c
) {
1010 netdev
= NETDEV(c
->macsec
);
1012 if (section_is_invalid(c
->section
))
1015 if (ether_addr_is_null(&c
->sci
.mac
))
1016 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
1017 "%s: MACsec receive channel without MAC address configured. "
1018 "Ignoring [MACsecReceiveChannel] section from line %u",
1019 c
->section
->filename
, c
->section
->line
);
1021 if (c
->sci
.port
== 0)
1022 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
1023 "%s: MACsec receive channel without port configured. "
1024 "Ignoring [MACsecReceiveChannel] section from line %u",
1025 c
->section
->filename
, c
->section
->line
);
1027 r
= ordered_hashmap_ensure_allocated(&c
->macsec
->receive_channels
, &uint64_hash_ops
);
1031 r
= ordered_hashmap_put(c
->macsec
->receive_channels
, &c
->sci
.as_uint64
, c
);
1033 return log_netdev_error_errno(netdev
, r
,
1034 "%s: Multiple [MACsecReceiveChannel] sections have same SCI, "
1035 "Ignoring [MACsecReceiveChannel] section from line %u",
1036 c
->section
->filename
, c
->section
->line
);
1038 return log_netdev_error_errno(netdev
, r
,
1039 "%s: Failed to store [MACsecReceiveChannel] section at hashmap, "
1040 "Ignoring [MACsecReceiveChannel] section from line %u",
1041 c
->section
->filename
, c
->section
->line
);
1045 static int macsec_transmit_association_verify(TransmitAssociation
*t
) {
1052 netdev
= NETDEV(t
->macsec
);
1054 if (section_is_invalid(t
->section
))
1057 if (t
->sa
.packet_number
== 0)
1058 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
1059 "%s: MACsec transmit secure association without PacketNumber= configured. "
1060 "Ignoring [MACsecTransmitAssociation] section from line %u",
1061 t
->section
->filename
, t
->section
->line
);
1063 r
= macsec_read_key_file(netdev
, &t
->sa
);
1067 if (t
->sa
.key_len
<= 0)
1068 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
1069 "%s: MACsec transmit secure association without key configured. "
1070 "Ignoring [MACsecTransmitAssociation] section from line %u",
1071 t
->section
->filename
, t
->section
->line
);
1076 static int macsec_receive_association_verify(ReceiveAssociation
*a
) {
1084 netdev
= NETDEV(a
->macsec
);
1086 if (section_is_invalid(a
->section
))
1089 r
= macsec_read_key_file(netdev
, &a
->sa
);
1093 if (a
->sa
.key_len
<= 0)
1094 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
1095 "%s: MACsec receive secure association without key configured. "
1096 "Ignoring [MACsecReceiveAssociation] section from line %u",
1097 a
->section
->filename
, a
->section
->line
);
1099 if (ether_addr_is_null(&a
->sci
.mac
))
1100 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
1101 "%s: MACsec receive secure association without MAC address configured. "
1102 "Ignoring [MACsecReceiveAssociation] section from line %u",
1103 a
->section
->filename
, a
->section
->line
);
1105 if (a
->sci
.port
== 0)
1106 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
1107 "%s: MACsec receive secure association without port configured. "
1108 "Ignoring [MACsecReceiveAssociation] section from line %u",
1109 a
->section
->filename
, a
->section
->line
);
1111 c
= ordered_hashmap_get(a
->macsec
->receive_channels
, &a
->sci
.as_uint64
);
1113 _cleanup_(macsec_receive_channel_freep
) ReceiveChannel
*new_channel
= NULL
;
1115 r
= macsec_receive_channel_new(a
->macsec
, a
->sci
.as_uint64
, &new_channel
);
1119 r
= ordered_hashmap_ensure_allocated(&a
->macsec
->receive_channels
, &uint64_hash_ops
);
1123 r
= ordered_hashmap_put(a
->macsec
->receive_channels
, &new_channel
->sci
.as_uint64
, new_channel
);
1125 return log_netdev_error_errno(netdev
, r
,
1126 "%s: Failed to store receive channel at hashmap, "
1127 "Ignoring [MACsecReceiveAssociation] section from line %u",
1128 a
->section
->filename
, a
->section
->line
);
1129 c
= TAKE_PTR(new_channel
);
1131 if (c
->n_rxsa
>= MACSEC_MAX_ASSOCIATION_NUMBER
)
1132 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(ERANGE
),
1133 "%s: Too many [MACsecReceiveAssociation] sections for the same receive channel, "
1134 "Ignoring [MACsecReceiveAssociation] section from line %u",
1135 a
->section
->filename
, a
->section
->line
);
1137 a
->sa
.association_number
= c
->n_rxsa
;
1138 c
->rxsa
[c
->n_rxsa
++] = a
;
1143 static int netdev_macsec_verify(NetDev
*netdev
, const char *filename
) {
1144 MACsec
*v
= MACSEC(netdev
);
1145 TransmitAssociation
*a
;
1146 ReceiveAssociation
*n
;
1149 uint8_t an
, encoding_an
;
1150 bool use_for_encoding
;
1157 ORDERED_HASHMAP_FOREACH(c
, v
->receive_channels_by_section
, i
) {
1158 r
= macsec_receive_channel_verify(c
);
1160 macsec_receive_channel_free(c
);
1164 use_for_encoding
= false;
1166 ORDERED_HASHMAP_FOREACH(a
, v
->transmit_associations_by_section
, i
) {
1167 r
= macsec_transmit_association_verify(a
);
1169 macsec_transmit_association_free(a
);
1173 if (an
>= MACSEC_MAX_ASSOCIATION_NUMBER
) {
1174 log_netdev_error(netdev
,
1175 "%s: Too many [MACsecTransmitAssociation] sections configured. "
1176 "Ignoring [MACsecTransmitAssociation] section from line %u",
1177 a
->section
->filename
, a
->section
->line
);
1178 macsec_transmit_association_free(a
);
1182 a
->sa
.association_number
= an
++;
1184 if (a
->sa
.use_for_encoding
> 0) {
1185 if (use_for_encoding
) {
1186 log_netdev_warning(netdev
,
1187 "%s: Multiple security associations are set to be used for transmit channel."
1188 "Disabling UseForEncoding= in [MACsecTransmitAssociation] section from line %u",
1189 a
->section
->filename
, a
->section
->line
);
1190 a
->sa
.use_for_encoding
= false;
1192 encoding_an
= a
->sa
.association_number
;
1193 use_for_encoding
= true;
1198 assert(encoding_an
< MACSEC_MAX_ASSOCIATION_NUMBER
);
1199 v
->encoding_an
= encoding_an
;
1201 ORDERED_HASHMAP_FOREACH(n
, v
->receive_associations_by_section
, i
) {
1202 r
= macsec_receive_association_verify(n
);
1204 macsec_receive_association_free(n
);
1210 static void macsec_init(NetDev
*netdev
) {
1222 static void macsec_done(NetDev
*netdev
) {
1231 ordered_hashmap_free_with_destructor(t
->receive_channels
, macsec_receive_channel_free
);
1232 ordered_hashmap_free_with_destructor(t
->receive_channels_by_section
, macsec_receive_channel_free
);
1233 ordered_hashmap_free_with_destructor(t
->transmit_associations_by_section
, macsec_transmit_association_free
);
1234 ordered_hashmap_free_with_destructor(t
->receive_associations_by_section
, macsec_receive_association_free
);
1237 const NetDevVTable macsec_vtable
= {
1238 .object_size
= sizeof(MACsec
),
1239 .init
= macsec_init
,
1240 .sections
= NETDEV_COMMON_SECTIONS
"MACsec\0MACsecReceiveChannel\0MACsecTransmitAssociation\0MACsecReceiveAssociation\0",
1241 .fill_message_create
= netdev_macsec_fill_message_create
,
1242 .post_create
= netdev_macsec_configure
,
1243 .done
= macsec_done
,
1244 .create_type
= NETDEV_CREATE_STACKED
,
1245 .config_verify
= netdev_macsec_verify
,
1246 .generate_mac
= true,