LCOV - code coverage report
Current view: top level - network/netdev - macsec.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 0 650 0.0 %
Date: 2019-08-23 13:36:53 Functions: 0 45 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 610 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <netinet/in.h>
       4                 :            : #include <linux/if_ether.h>
       5                 :            : #include <linux/if_macsec.h>
       6                 :            : #include <linux/genetlink.h>
       7                 :            : 
       8                 :            : #include "conf-parser.h"
       9                 :            : #include "fileio.h"
      10                 :            : #include "hashmap.h"
      11                 :            : #include "hexdecoct.h"
      12                 :            : #include "macsec.h"
      13                 :            : #include "memory-util.h"
      14                 :            : #include "missing.h"
      15                 :            : #include "netlink-util.h"
      16                 :            : #include "network-internal.h"
      17                 :            : #include "networkd-address.h"
      18                 :            : #include "networkd-manager.h"
      19                 :            : #include "path-util.h"
      20                 :            : #include "sd-netlink.h"
      21                 :            : #include "socket-util.h"
      22                 :            : #include "string-table.h"
      23                 :            : #include "string-util.h"
      24                 :            : #include "util.h"
      25                 :            : 
      26                 :          0 : static void security_association_clear(SecurityAssociation *sa) {
      27         [ #  # ]:          0 :         if (!sa)
      28                 :          0 :                 return;
      29                 :            : 
      30                 :          0 :         explicit_bzero_safe(sa->key, sa->key_len);
      31                 :          0 :         free(sa->key);
      32                 :          0 :         free(sa->key_file);
      33                 :            : }
      34                 :            : 
      35                 :          0 : static void security_association_init(SecurityAssociation *sa) {
      36         [ #  # ]:          0 :         assert(sa);
      37                 :            : 
      38                 :          0 :         sa->activate = -1;
      39                 :          0 :         sa->use_for_encoding = -1;
      40                 :          0 : }
      41                 :            : 
      42                 :          0 : static void macsec_receive_association_free(ReceiveAssociation *c) {
      43         [ #  # ]:          0 :         if (!c)
      44                 :          0 :                 return;
      45                 :            : 
      46   [ #  #  #  # ]:          0 :         if (c->macsec && c->section)
      47                 :          0 :                 ordered_hashmap_remove(c->macsec->receive_associations_by_section, c->section);
      48                 :            : 
      49                 :          0 :         network_config_section_free(c->section);
      50                 :          0 :         security_association_clear(&c->sa);
      51                 :            : 
      52                 :          0 :         free(c);
      53                 :            : }
      54                 :            : 
      55   [ #  #  #  # ]:          0 : DEFINE_NETWORK_SECTION_FUNCTIONS(ReceiveAssociation, macsec_receive_association_free);
      56                 :            : 
      57                 :          0 : static int macsec_receive_association_new_static(MACsec *s, const char *filename, unsigned section_line, ReceiveAssociation **ret) {
      58                 :          0 :         _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
      59                 :          0 :         _cleanup_(macsec_receive_association_freep) ReceiveAssociation *c = NULL;
      60                 :            :         int r;
      61                 :            : 
      62         [ #  # ]:          0 :         assert(s);
      63         [ #  # ]:          0 :         assert(ret);
      64         [ #  # ]:          0 :         assert(filename);
      65         [ #  # ]:          0 :         assert(section_line > 0);
      66                 :            : 
      67                 :          0 :         r = network_config_section_new(filename, section_line, &n);
      68         [ #  # ]:          0 :         if (r < 0)
      69                 :          0 :                 return r;
      70                 :            : 
      71                 :          0 :         c = ordered_hashmap_get(s->receive_associations_by_section, n);
      72         [ #  # ]:          0 :         if (c) {
      73                 :          0 :                 *ret = TAKE_PTR(c);
      74                 :          0 :                 return 0;
      75                 :            :         }
      76                 :            : 
      77                 :          0 :         c = new(ReceiveAssociation, 1);
      78         [ #  # ]:          0 :         if (!c)
      79                 :          0 :                 return -ENOMEM;
      80                 :            : 
      81                 :          0 :         *c = (ReceiveAssociation) {
      82                 :            :                 .macsec = s,
      83                 :          0 :                 .section = TAKE_PTR(n),
      84                 :            :         };
      85                 :            : 
      86                 :          0 :         security_association_init(&c->sa);
      87                 :            : 
      88                 :          0 :         r = ordered_hashmap_ensure_allocated(&s->receive_associations_by_section, &network_config_hash_ops);
      89         [ #  # ]:          0 :         if (r < 0)
      90                 :          0 :                 return r;
      91                 :            : 
      92                 :          0 :         r = ordered_hashmap_put(s->receive_associations_by_section, c->section, c);
      93         [ #  # ]:          0 :         if (r < 0)
      94                 :          0 :                 return r;
      95                 :            : 
      96                 :          0 :         *ret = TAKE_PTR(c);
      97                 :            : 
      98                 :          0 :         return 0;
      99                 :            : }
     100                 :            : 
     101                 :          0 : static void macsec_receive_channel_free(ReceiveChannel *c) {
     102         [ #  # ]:          0 :         if (!c)
     103                 :          0 :                 return;
     104                 :            : 
     105         [ #  # ]:          0 :         if (c->macsec) {
     106         [ #  # ]:          0 :                 if (c->sci.as_uint64 > 0)
     107                 :          0 :                         ordered_hashmap_remove(c->macsec->receive_channels, &c->sci.as_uint64);
     108                 :            : 
     109         [ #  # ]:          0 :                 if (c->section)
     110                 :          0 :                         ordered_hashmap_remove(c->macsec->receive_channels_by_section, c->section);
     111                 :            :         }
     112                 :            : 
     113                 :          0 :         network_config_section_free(c->section);
     114                 :            : 
     115                 :          0 :         free(c);
     116                 :            : }
     117                 :            : 
     118   [ #  #  #  # ]:          0 : DEFINE_NETWORK_SECTION_FUNCTIONS(ReceiveChannel, macsec_receive_channel_free);
     119                 :            : 
     120                 :          0 : static int macsec_receive_channel_new(MACsec *s, uint64_t sci, ReceiveChannel **ret) {
     121                 :            :         ReceiveChannel *c;
     122                 :            : 
     123         [ #  # ]:          0 :         assert(s);
     124                 :            : 
     125                 :          0 :         c = new(ReceiveChannel, 1);
     126         [ #  # ]:          0 :         if (!c)
     127                 :          0 :                 return -ENOMEM;
     128                 :            : 
     129                 :          0 :         *c = (ReceiveChannel) {
     130                 :            :                 .macsec = s,
     131                 :            :                 .sci.as_uint64 = sci,
     132                 :            :         };
     133                 :            : 
     134                 :          0 :         *ret = c;
     135                 :          0 :         return 0;
     136                 :            : }
     137                 :            : 
     138                 :          0 : static int macsec_receive_channel_new_static(MACsec *s, const char *filename, unsigned section_line, ReceiveChannel **ret) {
     139                 :          0 :         _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
     140                 :          0 :         _cleanup_(macsec_receive_channel_freep) ReceiveChannel *c = NULL;
     141                 :            :         int r;
     142                 :            : 
     143         [ #  # ]:          0 :         assert(s);
     144         [ #  # ]:          0 :         assert(ret);
     145         [ #  # ]:          0 :         assert(filename);
     146         [ #  # ]:          0 :         assert(section_line > 0);
     147                 :            : 
     148                 :          0 :         r = network_config_section_new(filename, section_line, &n);
     149         [ #  # ]:          0 :         if (r < 0)
     150                 :          0 :                 return r;
     151                 :            : 
     152                 :          0 :         c = ordered_hashmap_get(s->receive_channels_by_section, n);
     153         [ #  # ]:          0 :         if (c) {
     154                 :          0 :                 *ret = TAKE_PTR(c);
     155                 :          0 :                 return 0;
     156                 :            :         }
     157                 :            : 
     158                 :          0 :         r = macsec_receive_channel_new(s, 0, &c);
     159         [ #  # ]:          0 :         if (r < 0)
     160                 :          0 :                 return r;
     161                 :            : 
     162                 :          0 :         c->section = TAKE_PTR(n);
     163                 :            : 
     164                 :          0 :         r = ordered_hashmap_ensure_allocated(&s->receive_channels_by_section, &network_config_hash_ops);
     165         [ #  # ]:          0 :         if (r < 0)
     166                 :          0 :                 return r;
     167                 :            : 
     168                 :          0 :         r = ordered_hashmap_put(s->receive_channels_by_section, c->section, c);
     169         [ #  # ]:          0 :         if (r < 0)
     170                 :          0 :                 return r;
     171                 :            : 
     172                 :          0 :         *ret = TAKE_PTR(c);
     173                 :            : 
     174                 :          0 :         return 0;
     175                 :            : }
     176                 :            : 
     177                 :          0 : static void macsec_transmit_association_free(TransmitAssociation *a) {
     178         [ #  # ]:          0 :         if (!a)
     179                 :          0 :                 return;
     180                 :            : 
     181   [ #  #  #  # ]:          0 :         if (a->macsec && a->section)
     182                 :          0 :                 ordered_hashmap_remove(a->macsec->transmit_associations_by_section, a->section);
     183                 :            : 
     184                 :          0 :         network_config_section_free(a->section);
     185                 :          0 :         security_association_clear(&a->sa);
     186                 :            : 
     187                 :          0 :         free(a);
     188                 :            : }
     189                 :            : 
     190   [ #  #  #  # ]:          0 : DEFINE_NETWORK_SECTION_FUNCTIONS(TransmitAssociation, macsec_transmit_association_free);
     191                 :            : 
     192                 :          0 : static int macsec_transmit_association_new_static(MACsec *s, const char *filename, unsigned section_line, TransmitAssociation **ret) {
     193                 :          0 :         _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
     194                 :          0 :         _cleanup_(macsec_transmit_association_freep) TransmitAssociation *a = NULL;
     195                 :            :         int r;
     196                 :            : 
     197         [ #  # ]:          0 :         assert(s);
     198         [ #  # ]:          0 :         assert(ret);
     199         [ #  # ]:          0 :         assert(filename);
     200         [ #  # ]:          0 :         assert(section_line > 0);
     201                 :            : 
     202                 :          0 :         r = network_config_section_new(filename, section_line, &n);
     203         [ #  # ]:          0 :         if (r < 0)
     204                 :          0 :                 return r;
     205                 :            : 
     206                 :          0 :         a = ordered_hashmap_get(s->transmit_associations_by_section, n);
     207         [ #  # ]:          0 :         if (a) {
     208                 :          0 :                 *ret = TAKE_PTR(a);
     209                 :          0 :                 return 0;
     210                 :            :         }
     211                 :            : 
     212                 :          0 :         a = new(TransmitAssociation, 1);
     213         [ #  # ]:          0 :         if (!a)
     214                 :          0 :                 return -ENOMEM;
     215                 :            : 
     216                 :          0 :         *a = (TransmitAssociation) {
     217                 :            :                 .macsec = s,
     218                 :          0 :                 .section = TAKE_PTR(n),
     219                 :            :         };
     220                 :            : 
     221                 :          0 :         security_association_init(&a->sa);
     222                 :            : 
     223                 :          0 :         r = ordered_hashmap_ensure_allocated(&s->transmit_associations_by_section, &network_config_hash_ops);
     224         [ #  # ]:          0 :         if (r < 0)
     225                 :          0 :                 return r;
     226                 :            : 
     227                 :          0 :         r = ordered_hashmap_put(s->transmit_associations_by_section, a->section, a);
     228         [ #  # ]:          0 :         if (r < 0)
     229                 :          0 :                 return r;
     230                 :            : 
     231                 :          0 :         *ret = TAKE_PTR(a);
     232                 :            : 
     233                 :          0 :         return 0;
     234                 :            : }
     235                 :            : 
     236                 :          0 : static int netdev_macsec_fill_message(NetDev *netdev, int command, sd_netlink_message **ret) {
     237                 :          0 :         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
     238                 :            :         int r;
     239                 :            : 
     240         [ #  # ]:          0 :         assert(netdev);
     241         [ #  # ]:          0 :         assert(netdev->ifindex > 0);
     242                 :            : 
     243                 :          0 :         r = sd_genl_message_new(netdev->manager->genl, SD_GENL_MACSEC, command, &m);
     244         [ #  # ]:          0 :         if (r < 0)
     245         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, r, "Failed to create generic netlink message: %m");
     246                 :            : 
     247                 :          0 :         r = sd_netlink_message_append_u32(m, MACSEC_ATTR_IFINDEX, netdev->ifindex);
     248         [ #  # ]:          0 :         if (r < 0)
     249         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, r, "Could not append MACSEC_ATTR_IFINDEX attribute: %m");
     250                 :            : 
     251                 :          0 :         *ret = TAKE_PTR(m);
     252                 :            : 
     253                 :          0 :         return 0;
     254                 :            : }
     255                 :            : 
     256                 :          0 : static int netdev_macsec_fill_message_sci(NetDev *netdev, MACsecSCI *sci, sd_netlink_message *m) {
     257                 :            :         int r;
     258                 :            : 
     259         [ #  # ]:          0 :         assert(netdev);
     260         [ #  # ]:          0 :         assert(m);
     261         [ #  # ]:          0 :         assert(sci);
     262                 :            : 
     263                 :          0 :         r = sd_netlink_message_open_container(m, MACSEC_ATTR_RXSC_CONFIG);
     264         [ #  # ]:          0 :         if (r < 0)
     265         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, r, "Could not append MACSEC_ATTR_RXSC_CONFIG attribute: %m");
     266                 :            : 
     267                 :          0 :         r = sd_netlink_message_append_u64(m, MACSEC_RXSC_ATTR_SCI, sci->as_uint64);
     268         [ #  # ]:          0 :         if (r < 0)
     269         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, r, "Could not append MACSEC_RXSC_ATTR_SCI attribute: %m");
     270                 :            : 
     271                 :          0 :         r = sd_netlink_message_close_container(m);
     272         [ #  # ]:          0 :         if (r < 0)
     273         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, r, "Could not append MACSEC_ATTR_RXSC_CONFIG attribute: %m");
     274                 :            : 
     275                 :          0 :         return 0;
     276                 :            : }
     277                 :            : 
     278                 :          0 : static int netdev_macsec_fill_message_sa(NetDev *netdev, SecurityAssociation *a, sd_netlink_message *m) {
     279                 :            :         int r;
     280                 :            : 
     281         [ #  # ]:          0 :         assert(netdev);
     282         [ #  # ]:          0 :         assert(a);
     283         [ #  # ]:          0 :         assert(m);
     284                 :            : 
     285                 :          0 :         r = sd_netlink_message_open_container(m, MACSEC_ATTR_SA_CONFIG);
     286         [ #  # ]:          0 :         if (r < 0)
     287         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, r, "Could not append MACSEC_ATTR_SA_CONFIG attribute: %m");
     288                 :            : 
     289                 :          0 :         r = sd_netlink_message_append_u8(m, MACSEC_SA_ATTR_AN, a->association_number);
     290         [ #  # ]:          0 :         if (r < 0)
     291         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, r, "Could not append MACSEC_SA_ATTR_AN attribute: %m");
     292                 :            : 
     293         [ #  # ]:          0 :         if (a->packet_number > 0) {
     294                 :          0 :                 r = sd_netlink_message_append_u32(m, MACSEC_SA_ATTR_PN, a->packet_number);
     295         [ #  # ]:          0 :                 if (r < 0)
     296         [ #  # ]:          0 :                         return log_netdev_error_errno(netdev, r, "Could not append MACSEC_SA_ATTR_PN attribute: %m");
     297                 :            :         }
     298                 :            : 
     299         [ #  # ]:          0 :         if (a->key_len > 0) {
     300                 :          0 :                 r = sd_netlink_message_append_data(m, MACSEC_SA_ATTR_KEYID, a->key_id, MACSEC_KEYID_LEN);
     301         [ #  # ]:          0 :                 if (r < 0)
     302         [ #  # ]:          0 :                         return log_netdev_error_errno(netdev, r, "Could not append MACSEC_SA_ATTR_KEYID attribute: %m");
     303                 :            : 
     304                 :          0 :                 r = sd_netlink_message_append_data(m, MACSEC_SA_ATTR_KEY, a->key, a->key_len);
     305         [ #  # ]:          0 :                 if (r < 0)
     306         [ #  # ]:          0 :                         return log_netdev_error_errno(netdev, r, "Could not append MACSEC_SA_ATTR_KEY attribute: %m");
     307                 :            :         }
     308                 :            : 
     309         [ #  # ]:          0 :         if (a->activate >= 0) {
     310                 :          0 :                 r = sd_netlink_message_append_u8(m, MACSEC_SA_ATTR_ACTIVE, a->activate);
     311         [ #  # ]:          0 :                 if (r < 0)
     312         [ #  # ]:          0 :                         return log_netdev_error_errno(netdev, r, "Could not append MACSEC_SA_ATTR_ACTIVE attribute: %m");
     313                 :            :         }
     314                 :            : 
     315                 :          0 :         r = sd_netlink_message_close_container(m);
     316         [ #  # ]:          0 :         if (r < 0)
     317         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, r, "Could not append MACSEC_ATTR_SA_CONFIG attribute: %m");
     318                 :            : 
     319                 :          0 :         return 0;
     320                 :            : }
     321                 :            : 
     322                 :          0 : static int macsec_receive_association_handler(sd_netlink *rtnl, sd_netlink_message *m, NetDev *netdev) {
     323                 :            :         int r;
     324                 :            : 
     325         [ #  # ]:          0 :         assert(netdev);
     326         [ #  # ]:          0 :         assert(netdev->state != _NETDEV_STATE_INVALID);
     327                 :            : 
     328                 :          0 :         r = sd_netlink_message_get_errno(m);
     329         [ #  # ]:          0 :         if (r == -EEXIST)
     330         [ #  # ]:          0 :                 log_netdev_info(netdev,
     331                 :            :                                 "MACsec receive secure association exists, "
     332                 :            :                                 "using existing without changing its parameters");
     333         [ #  # ]:          0 :         else if (r < 0) {
     334         [ #  # ]:          0 :                 log_netdev_warning_errno(netdev, r,
     335                 :            :                                          "Failed to add receive secure association: %m");
     336                 :          0 :                 netdev_drop(netdev);
     337                 :            : 
     338                 :          0 :                 return 1;
     339                 :            :         }
     340                 :            : 
     341         [ #  # ]:          0 :         log_netdev_debug(netdev, "Receive secure association is configured");
     342                 :            : 
     343                 :          0 :         return 1;
     344                 :            : }
     345                 :            : 
     346                 :          0 : static int netdev_macsec_configure_receive_association(NetDev *netdev, ReceiveAssociation *a) {
     347                 :          0 :         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
     348                 :            :         int r;
     349                 :            : 
     350         [ #  # ]:          0 :         assert(netdev);
     351         [ #  # ]:          0 :         assert(a);
     352                 :            : 
     353                 :          0 :         r = netdev_macsec_fill_message(netdev, MACSEC_CMD_ADD_RXSA, &m);
     354         [ #  # ]:          0 :         if (r < 0)
     355                 :          0 :                 return r;
     356                 :            : 
     357                 :          0 :         r = netdev_macsec_fill_message_sa(netdev, &a->sa, m);
     358         [ #  # ]:          0 :         if (r < 0)
     359                 :          0 :                 return r;
     360                 :            : 
     361                 :          0 :         r = netdev_macsec_fill_message_sci(netdev, &a->sci, m);
     362         [ #  # ]:          0 :         if (r < 0)
     363                 :          0 :                 return r;
     364                 :            : 
     365                 :          0 :         r = netlink_call_async(netdev->manager->genl, NULL, m, macsec_receive_association_handler,
     366                 :            :                                netdev_destroy_callback, netdev);
     367         [ #  # ]:          0 :         if (r < 0)
     368         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, r, "Failed to configure receive secure association: %m");
     369                 :            : 
     370                 :          0 :         netdev_ref(netdev);
     371                 :            : 
     372                 :          0 :         return 0;
     373                 :            : }
     374                 :            : 
     375                 :          0 : static int macsec_receive_channel_handler(sd_netlink *rtnl, sd_netlink_message *m, ReceiveChannel *c) {
     376                 :            :         NetDev *netdev;
     377                 :            :         unsigned i;
     378                 :            :         int r;
     379                 :            : 
     380         [ #  # ]:          0 :         assert(c);
     381         [ #  # ]:          0 :         assert(c->macsec);
     382                 :            : 
     383                 :          0 :         netdev = NETDEV(c->macsec);
     384                 :            : 
     385         [ #  # ]:          0 :         assert(netdev->state != _NETDEV_STATE_INVALID);
     386                 :            : 
     387                 :          0 :         r = sd_netlink_message_get_errno(m);
     388         [ #  # ]:          0 :         if (r == -EEXIST)
     389         [ #  # ]:          0 :                 log_netdev_debug(netdev,
     390                 :            :                                  "MACsec receive channel exists, "
     391                 :            :                                  "using existing without changing its parameters");
     392         [ #  # ]:          0 :         else if (r < 0) {
     393         [ #  # ]:          0 :                 log_netdev_warning_errno(netdev, r,
     394                 :            :                                          "Failed to add receive secure channel: %m");
     395                 :          0 :                 netdev_drop(netdev);
     396                 :            : 
     397                 :          0 :                 return 1;
     398                 :            :         }
     399                 :            : 
     400         [ #  # ]:          0 :         log_netdev_debug(netdev, "Receive channel is configured");
     401                 :            : 
     402         [ #  # ]:          0 :         for (i = 0; i < c->n_rxsa; i++) {
     403                 :          0 :                 r = netdev_macsec_configure_receive_association(netdev, c->rxsa[i]);
     404         [ #  # ]:          0 :                 if (r < 0) {
     405         [ #  # ]:          0 :                         log_netdev_warning_errno(netdev, r,
     406                 :            :                                                  "Failed to configure receive security association: %m");
     407                 :          0 :                         netdev_drop(netdev);
     408                 :          0 :                         return 1;
     409                 :            :                 }
     410                 :            :         }
     411                 :            : 
     412                 :          0 :         return 1;
     413                 :            : }
     414                 :            : 
     415                 :          0 : static void receive_channel_destroy_callback(ReceiveChannel *c) {
     416         [ #  # ]:          0 :         assert(c);
     417         [ #  # ]:          0 :         assert(c->macsec);
     418                 :            : 
     419                 :          0 :         netdev_unref(NETDEV(c->macsec));
     420                 :          0 : }
     421                 :            : 
     422                 :          0 : static int netdev_macsec_configure_receive_channel(NetDev *netdev, ReceiveChannel *c) {
     423                 :          0 :         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
     424                 :            :         int r;
     425                 :            : 
     426         [ #  # ]:          0 :         assert(netdev);
     427         [ #  # ]:          0 :         assert(c);
     428                 :            : 
     429                 :          0 :         r = netdev_macsec_fill_message(netdev, MACSEC_CMD_ADD_RXSC, &m);
     430         [ #  # ]:          0 :         if (r < 0)
     431                 :          0 :                 return r;
     432                 :            : 
     433                 :          0 :         r = netdev_macsec_fill_message_sci(netdev, &c->sci, m);
     434         [ #  # ]:          0 :         if (r < 0)
     435                 :          0 :                 return r;
     436                 :            : 
     437                 :          0 :         r = netlink_call_async(netdev->manager->genl, NULL, m, macsec_receive_channel_handler,
     438                 :            :                                receive_channel_destroy_callback, c);
     439         [ #  # ]:          0 :         if (r < 0)
     440         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, r, "Failed to configure receive channel: %m");
     441                 :            : 
     442                 :          0 :         netdev_ref(netdev);
     443                 :            : 
     444                 :          0 :         return 0;
     445                 :            : }
     446                 :            : 
     447                 :          0 : static int macsec_transmit_association_handler(sd_netlink *rtnl, sd_netlink_message *m, NetDev *netdev) {
     448                 :            :         int r;
     449                 :            : 
     450         [ #  # ]:          0 :         assert(netdev);
     451         [ #  # ]:          0 :         assert(netdev->state != _NETDEV_STATE_INVALID);
     452                 :            : 
     453                 :          0 :         r = sd_netlink_message_get_errno(m);
     454         [ #  # ]:          0 :         if (r == -EEXIST)
     455         [ #  # ]:          0 :                 log_netdev_info(netdev,
     456                 :            :                                 "MACsec transmit secure association exists, "
     457                 :            :                                 "using existing without changing its parameters");
     458         [ #  # ]:          0 :         else if (r < 0) {
     459         [ #  # ]:          0 :                 log_netdev_warning_errno(netdev, r,
     460                 :            :                                          "Failed to add transmit secure association: %m");
     461                 :          0 :                 netdev_drop(netdev);
     462                 :            : 
     463                 :          0 :                 return 1;
     464                 :            :         }
     465                 :            : 
     466         [ #  # ]:          0 :         log_netdev_debug(netdev, "Transmit secure association is configured");
     467                 :            : 
     468                 :          0 :         return 1;
     469                 :            : }
     470                 :            : 
     471                 :          0 : static int netdev_macsec_configure_transmit_association(NetDev *netdev, TransmitAssociation *a) {
     472                 :          0 :         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
     473                 :            :         int r;
     474                 :            : 
     475         [ #  # ]:          0 :         assert(netdev);
     476         [ #  # ]:          0 :         assert(a);
     477                 :            : 
     478                 :          0 :         r = netdev_macsec_fill_message(netdev, MACSEC_CMD_ADD_TXSA, &m);
     479         [ #  # ]:          0 :         if (r < 0)
     480                 :          0 :                 return r;
     481                 :            : 
     482                 :          0 :         r = netdev_macsec_fill_message_sa(netdev, &a->sa, m);
     483         [ #  # ]:          0 :         if (r < 0)
     484                 :          0 :                 return r;
     485                 :            : 
     486                 :          0 :         r = netlink_call_async(netdev->manager->genl, NULL, m, macsec_transmit_association_handler,
     487                 :            :                                netdev_destroy_callback, netdev);
     488         [ #  # ]:          0 :         if (r < 0)
     489         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, r, "Failed to configure transmit secure association: %m");
     490                 :            : 
     491                 :          0 :         netdev_ref(netdev);
     492                 :            : 
     493                 :          0 :         return 0;
     494                 :            : }
     495                 :            : 
     496                 :          0 : static int netdev_macsec_configure(NetDev *netdev, Link *link, sd_netlink_message *m) {
     497                 :            :         TransmitAssociation *a;
     498                 :            :         ReceiveChannel *c;
     499                 :            :         Iterator i;
     500                 :            :         MACsec *s;
     501                 :            :         int r;
     502                 :            : 
     503         [ #  # ]:          0 :         assert(netdev);
     504                 :          0 :         s = MACSEC(netdev);
     505         [ #  # ]:          0 :         assert(s);
     506                 :            : 
     507         [ #  # ]:          0 :         ORDERED_HASHMAP_FOREACH(a, s->transmit_associations_by_section, i) {
     508                 :          0 :                 r = netdev_macsec_configure_transmit_association(netdev, a);
     509         [ #  # ]:          0 :                 if (r < 0)
     510                 :          0 :                         return r;
     511                 :            :         }
     512                 :            : 
     513         [ #  # ]:          0 :         ORDERED_HASHMAP_FOREACH(c, s->receive_channels, i) {
     514                 :          0 :                 r = netdev_macsec_configure_receive_channel(netdev, c);
     515         [ #  # ]:          0 :                 if (r < 0)
     516                 :          0 :                         return r;
     517                 :            :         }
     518                 :            : 
     519                 :          0 :         return 0;
     520                 :            : }
     521                 :            : 
     522                 :          0 : static int netdev_macsec_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
     523                 :            :         MACsec *v;
     524                 :            :         int r;
     525                 :            : 
     526         [ #  # ]:          0 :         assert(netdev);
     527         [ #  # ]:          0 :         assert(m);
     528                 :            : 
     529                 :          0 :         v = MACSEC(netdev);
     530                 :            : 
     531         [ #  # ]:          0 :         if (v->port > 0) {
     532                 :          0 :                 r = sd_netlink_message_append_u16(m, IFLA_MACSEC_PORT, v->port);
     533         [ #  # ]:          0 :                 if (r < 0)
     534         [ #  # ]:          0 :                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_MACSEC_PORT attribute: %m");
     535                 :            :         }
     536                 :            : 
     537         [ #  # ]:          0 :         if (v->encrypt >= 0) {
     538                 :          0 :                 r = sd_netlink_message_append_u8(m, IFLA_MACSEC_ENCRYPT, v->encrypt);
     539         [ #  # ]:          0 :                 if (r < 0)
     540         [ #  # ]:          0 :                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_MACSEC_ENCRYPT attribute: %m");
     541                 :            :         }
     542                 :            : 
     543                 :          0 :         r = sd_netlink_message_append_u8(m, IFLA_MACSEC_ENCODING_SA, v->encoding_an);
     544         [ #  # ]:          0 :         if (r < 0)
     545         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_MACSEC_ENCODING_SA attribute: %m");
     546                 :            : 
     547                 :          0 :         return r;
     548                 :            : }
     549                 :            : 
     550                 :          0 : int config_parse_macsec_port(
     551                 :            :                 const char *unit,
     552                 :            :                 const char *filename,
     553                 :            :                 unsigned line,
     554                 :            :                 const char *section,
     555                 :            :                 unsigned section_line,
     556                 :            :                 const char *lvalue,
     557                 :            :                 int ltype,
     558                 :            :                 const char *rvalue,
     559                 :            :                 void *data,
     560                 :            :                 void *userdata) {
     561                 :            : 
     562                 :          0 :         _cleanup_(macsec_receive_association_free_or_set_invalidp) ReceiveAssociation *b = NULL;
     563                 :          0 :         _cleanup_(macsec_receive_channel_free_or_set_invalidp) ReceiveChannel *c = NULL;
     564                 :          0 :         MACsec *s = userdata;
     565                 :            :         uint16_t port;
     566                 :            :         void *dest;
     567                 :            :         int r;
     568                 :            : 
     569         [ #  # ]:          0 :         assert(filename);
     570         [ #  # ]:          0 :         assert(section);
     571         [ #  # ]:          0 :         assert(lvalue);
     572         [ #  # ]:          0 :         assert(rvalue);
     573         [ #  # ]:          0 :         assert(data);
     574                 :            : 
     575                 :            :         /* This parses port used to make Secure Channel Identifier (SCI) */
     576                 :            : 
     577         [ #  # ]:          0 :         if (streq(section, "MACsec"))
     578                 :          0 :                 dest = &s->port;
     579         [ #  # ]:          0 :         else if (streq(section, "MACsecReceiveChannel")) {
     580                 :          0 :                 r = macsec_receive_channel_new_static(s, filename, section_line, &c);
     581         [ #  # ]:          0 :                 if (r < 0)
     582                 :          0 :                         return r;
     583                 :            : 
     584                 :          0 :                 dest = &c->sci.port;
     585                 :            :         } else {
     586         [ #  # ]:          0 :                 assert(streq(section, "MACsecReceiveAssociation"));
     587                 :            : 
     588                 :          0 :                 r = macsec_receive_association_new_static(s, filename, section_line, &b);
     589         [ #  # ]:          0 :                 if (r < 0)
     590                 :          0 :                         return r;
     591                 :            : 
     592                 :          0 :                 dest = &b->sci.port;
     593                 :            :         }
     594                 :            : 
     595                 :          0 :         r = parse_ip_port(rvalue, &port);
     596         [ #  # ]:          0 :         if (r < 0) {
     597         [ #  # ]:          0 :                 log_syntax(unit, LOG_ERR, filename, line, r,
     598                 :            :                            "Failed to parse port '%s' for secure channel identifier. Ignoring assignment: %m",
     599                 :            :                            rvalue);
     600                 :          0 :                 return 0;
     601                 :            :         }
     602                 :            : 
     603                 :          0 :         unaligned_write_be16(dest, port);
     604                 :            : 
     605                 :          0 :         TAKE_PTR(b);
     606                 :          0 :         TAKE_PTR(c);
     607                 :            : 
     608                 :          0 :         return 0;
     609                 :            : }
     610                 :            : 
     611                 :          0 : int config_parse_macsec_hw_address(
     612                 :            :                 const char *unit,
     613                 :            :                 const char *filename,
     614                 :            :                 unsigned line,
     615                 :            :                 const char *section,
     616                 :            :                 unsigned section_line,
     617                 :            :                 const char *lvalue,
     618                 :            :                 int ltype,
     619                 :            :                 const char *rvalue,
     620                 :            :                 void *data,
     621                 :            :                 void *userdata) {
     622                 :            : 
     623                 :          0 :         _cleanup_(macsec_receive_association_free_or_set_invalidp) ReceiveAssociation *b = NULL;
     624                 :          0 :         _cleanup_(macsec_receive_channel_free_or_set_invalidp) ReceiveChannel *c = NULL;
     625                 :          0 :         MACsec *s = userdata;
     626                 :            :         int r;
     627                 :            : 
     628         [ #  # ]:          0 :         assert(filename);
     629         [ #  # ]:          0 :         assert(section);
     630         [ #  # ]:          0 :         assert(lvalue);
     631         [ #  # ]:          0 :         assert(rvalue);
     632         [ #  # ]:          0 :         assert(data);
     633                 :            : 
     634         [ #  # ]:          0 :         if (streq(section, "MACsecReceiveChannel"))
     635                 :          0 :                 r = macsec_receive_channel_new_static(s, filename, section_line, &c);
     636                 :            :         else
     637                 :          0 :                 r = macsec_receive_association_new_static(s, filename, section_line, &b);
     638         [ #  # ]:          0 :         if (r < 0)
     639                 :          0 :                 return r;
     640                 :            : 
     641         [ #  # ]:          0 :         r = ether_addr_from_string(rvalue, b ? &b->sci.mac : &c->sci.mac);
     642         [ #  # ]:          0 :         if (r < 0) {
     643         [ #  # ]:          0 :                 log_syntax(unit, LOG_ERR, filename, line, r,
     644                 :            :                            "Failed to parse MAC address for secure channel identifier. "
     645                 :            :                            "Ignoring assignment: %s", rvalue);
     646                 :          0 :                 return 0;
     647                 :            :         }
     648                 :            : 
     649                 :          0 :         TAKE_PTR(b);
     650                 :          0 :         TAKE_PTR(c);
     651                 :            : 
     652                 :          0 :         return 0;
     653                 :            : }
     654                 :            : 
     655                 :          0 : int config_parse_macsec_packet_number(
     656                 :            :                 const char *unit,
     657                 :            :                 const char *filename,
     658                 :            :                 unsigned line,
     659                 :            :                 const char *section,
     660                 :            :                 unsigned section_line,
     661                 :            :                 const char *lvalue,
     662                 :            :                 int ltype,
     663                 :            :                 const char *rvalue,
     664                 :            :                 void *data,
     665                 :            :                 void *userdata) {
     666                 :            : 
     667                 :          0 :         _cleanup_(macsec_transmit_association_free_or_set_invalidp) TransmitAssociation *a = NULL;
     668                 :          0 :         _cleanup_(macsec_receive_association_free_or_set_invalidp) ReceiveAssociation *b = NULL;
     669                 :          0 :         MACsec *s = userdata;
     670                 :            :         uint32_t val, *dest;
     671                 :            :         int r;
     672                 :            : 
     673         [ #  # ]:          0 :         assert(filename);
     674         [ #  # ]:          0 :         assert(section);
     675         [ #  # ]:          0 :         assert(lvalue);
     676         [ #  # ]:          0 :         assert(rvalue);
     677         [ #  # ]:          0 :         assert(data);
     678                 :            : 
     679         [ #  # ]:          0 :         if (streq(section, "MACsecTransmitAssociation"))
     680                 :          0 :                 r = macsec_transmit_association_new_static(s, filename, section_line, &a);
     681                 :            :         else
     682                 :          0 :                 r = macsec_receive_association_new_static(s, filename, section_line, &b);
     683         [ #  # ]:          0 :         if (r < 0)
     684                 :          0 :                 return r;
     685                 :            : 
     686         [ #  # ]:          0 :         dest = a ? &a->sa.packet_number : &b->sa.packet_number;
     687                 :            : 
     688                 :          0 :         r = safe_atou32(rvalue, &val);
     689         [ #  # ]:          0 :         if (r < 0) {
     690         [ #  # ]:          0 :                 log_syntax(unit, LOG_ERR, filename, line, r,
     691                 :            :                            "Failed to parse packet number. Ignoring assignment: %s", rvalue);
     692                 :          0 :                 return 0;
     693                 :            :         }
     694   [ #  #  #  # ]:          0 :         if (streq(section, "MACsecTransmitAssociation") && val == 0) {
     695         [ #  # ]:          0 :                 log_syntax(unit, LOG_ERR, filename, line, 0,
     696                 :            :                            "Invalid packet number. Ignoring assignment: %s", rvalue);
     697                 :          0 :                 return 0;
     698                 :            :         }
     699                 :            : 
     700                 :          0 :         *dest = val;
     701                 :          0 :         TAKE_PTR(a);
     702                 :          0 :         TAKE_PTR(b);
     703                 :            : 
     704                 :          0 :         return 0;
     705                 :            : }
     706                 :            : 
     707                 :          0 : int config_parse_macsec_key(
     708                 :            :                 const char *unit,
     709                 :            :                 const char *filename,
     710                 :            :                 unsigned line,
     711                 :            :                 const char *section,
     712                 :            :                 unsigned section_line,
     713                 :            :                 const char *lvalue,
     714                 :            :                 int ltype,
     715                 :            :                 const char *rvalue,
     716                 :            :                 void *data,
     717                 :            :                 void *userdata) {
     718                 :            : 
     719                 :          0 :         _cleanup_(macsec_transmit_association_free_or_set_invalidp) TransmitAssociation *a = NULL;
     720                 :          0 :         _cleanup_(macsec_receive_association_free_or_set_invalidp) ReceiveAssociation *b = NULL;
     721                 :          0 :         _cleanup_(erase_and_freep) void *p = NULL;
     722                 :          0 :         MACsec *s = userdata;
     723                 :            :         SecurityAssociation *dest;
     724                 :            :         size_t l;
     725                 :            :         int r;
     726                 :            : 
     727         [ #  # ]:          0 :         assert(filename);
     728         [ #  # ]:          0 :         assert(section);
     729         [ #  # ]:          0 :         assert(lvalue);
     730         [ #  # ]:          0 :         assert(rvalue);
     731         [ #  # ]:          0 :         assert(data);
     732                 :            : 
     733                 :          0 :         (void) warn_file_is_world_accessible(filename, NULL, unit, line);
     734                 :            : 
     735         [ #  # ]:          0 :         if (streq(section, "MACsecTransmitAssociation"))
     736                 :          0 :                 r = macsec_transmit_association_new_static(s, filename, section_line, &a);
     737                 :            :         else
     738                 :          0 :                 r = macsec_receive_association_new_static(s, filename, section_line, &b);
     739         [ #  # ]:          0 :         if (r < 0)
     740                 :          0 :                 return r;
     741                 :            : 
     742         [ #  # ]:          0 :         dest = a ? &a->sa : &b->sa;
     743                 :            : 
     744                 :          0 :         r = unhexmem_full(rvalue, strlen(rvalue), true, &p, &l);
     745         [ #  # ]:          0 :         if (r < 0) {
     746         [ #  # ]:          0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse key. Ignoring assignment: %m");
     747                 :          0 :                 return 0;
     748                 :            :         }
     749                 :            : 
     750         [ #  # ]:          0 :         if (l != 16) {
     751                 :            :                 /* See DEFAULT_SAK_LEN in drivers/net/macsec.c */
     752         [ #  # ]:          0 :                 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid key length (%zu). Ignoring assignment", l);
     753                 :          0 :                 return 0;
     754                 :            :         }
     755                 :            : 
     756                 :          0 :         explicit_bzero_safe(dest->key, dest->key_len);
     757                 :          0 :         free_and_replace(dest->key, p);
     758                 :          0 :         dest->key_len = l;
     759                 :            : 
     760                 :          0 :         TAKE_PTR(a);
     761                 :          0 :         TAKE_PTR(b);
     762                 :            : 
     763                 :          0 :         return 0;
     764                 :            : }
     765                 :            : 
     766                 :          0 : int config_parse_macsec_key_file(
     767                 :            :                 const char *unit,
     768                 :            :                 const char *filename,
     769                 :            :                 unsigned line,
     770                 :            :                 const char *section,
     771                 :            :                 unsigned section_line,
     772                 :            :                 const char *lvalue,
     773                 :            :                 int ltype,
     774                 :            :                 const char *rvalue,
     775                 :            :                 void *data,
     776                 :            :                 void *userdata) {
     777                 :            : 
     778                 :          0 :         _cleanup_(macsec_transmit_association_free_or_set_invalidp) TransmitAssociation *a = NULL;
     779                 :          0 :         _cleanup_(macsec_receive_association_free_or_set_invalidp) ReceiveAssociation *b = NULL;
     780                 :          0 :         _cleanup_free_ char *path = NULL;
     781                 :          0 :         MACsec *s = userdata;
     782                 :            :         char **dest;
     783                 :            :         int r;
     784                 :            : 
     785         [ #  # ]:          0 :         assert(filename);
     786         [ #  # ]:          0 :         assert(section);
     787         [ #  # ]:          0 :         assert(lvalue);
     788         [ #  # ]:          0 :         assert(rvalue);
     789         [ #  # ]:          0 :         assert(data);
     790                 :            : 
     791         [ #  # ]:          0 :         if (streq(section, "MACsecTransmitAssociation"))
     792                 :          0 :                 r = macsec_transmit_association_new_static(s, filename, section_line, &a);
     793                 :            :         else
     794                 :          0 :                 r = macsec_receive_association_new_static(s, filename, section_line, &b);
     795         [ #  # ]:          0 :         if (r < 0)
     796                 :          0 :                 return r;
     797                 :            : 
     798         [ #  # ]:          0 :         dest = a ? &a->sa.key_file : &b->sa.key_file;
     799                 :            : 
     800         [ #  # ]:          0 :         if (isempty(rvalue)) {
     801                 :          0 :                 *dest = mfree(*dest);
     802                 :          0 :                 return 0;
     803                 :            :         }
     804                 :            : 
     805                 :          0 :         path = strdup(rvalue);
     806         [ #  # ]:          0 :         if (!path)
     807                 :          0 :                 return log_oom();
     808                 :            : 
     809         [ #  # ]:          0 :         if (path_simplify_and_warn(path, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue) < 0)
     810                 :          0 :                 return 0;
     811                 :            : 
     812                 :          0 :         free_and_replace(*dest, path);
     813                 :          0 :         TAKE_PTR(a);
     814                 :          0 :         TAKE_PTR(b);
     815                 :            : 
     816                 :          0 :         return 0;
     817                 :            : }
     818                 :            : 
     819                 :          0 : int config_parse_macsec_key_id(
     820                 :            :                 const char *unit,
     821                 :            :                 const char *filename,
     822                 :            :                 unsigned line,
     823                 :            :                 const char *section,
     824                 :            :                 unsigned section_line,
     825                 :            :                 const char *lvalue,
     826                 :            :                 int ltype,
     827                 :            :                 const char *rvalue,
     828                 :            :                 void *data,
     829                 :            :                 void *userdata) {
     830                 :            : 
     831                 :          0 :         _cleanup_(macsec_transmit_association_free_or_set_invalidp) TransmitAssociation *a = NULL;
     832                 :          0 :         _cleanup_(macsec_receive_association_free_or_set_invalidp) ReceiveAssociation *b = NULL;
     833                 :          0 :         _cleanup_free_ void *p;
     834                 :          0 :         MACsec *s = userdata;
     835                 :            :         uint8_t *dest;
     836                 :            :         size_t l;
     837                 :            :         int r;
     838                 :            : 
     839         [ #  # ]:          0 :         assert(filename);
     840         [ #  # ]:          0 :         assert(section);
     841         [ #  # ]:          0 :         assert(lvalue);
     842         [ #  # ]:          0 :         assert(rvalue);
     843         [ #  # ]:          0 :         assert(data);
     844                 :            : 
     845         [ #  # ]:          0 :         if (streq(section, "MACsecTransmitAssociation"))
     846                 :          0 :                 r = macsec_transmit_association_new_static(s, filename, section_line, &a);
     847                 :            :         else
     848                 :          0 :                 r = macsec_receive_association_new_static(s, filename, section_line, &b);
     849         [ #  # ]:          0 :         if (r < 0)
     850                 :          0 :                 return r;
     851                 :            : 
     852                 :          0 :         r = unhexmem(rvalue, strlen(rvalue), &p, &l);
     853         [ #  # ]:          0 :         if (r < 0) {
     854         [ #  # ]:          0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse KeyId \"%s\": %m", rvalue);
     855                 :          0 :                 return 0;
     856                 :            :         }
     857         [ #  # ]:          0 :         if (l > MACSEC_KEYID_LEN)
     858         [ #  # ]:          0 :                 return log_syntax(unit, LOG_ERR, filename, line, 0,
     859                 :            :                                   "Specified KeyId is larger then the allowed maximum (%zu > %u), ignoring: %s",
     860                 :            :                                   l, MACSEC_KEYID_LEN, rvalue);
     861                 :            : 
     862         [ #  # ]:          0 :         dest = a ? a->sa.key_id : b->sa.key_id;
     863                 :          0 :         memcpy_safe(dest, p, l);
     864         [ #  # ]:          0 :         memzero(dest + l, MACSEC_KEYID_LEN - l);
     865                 :            : 
     866                 :          0 :         TAKE_PTR(a);
     867                 :          0 :         TAKE_PTR(b);
     868                 :            : 
     869                 :          0 :         return 0;
     870                 :            : }
     871                 :            : 
     872                 :          0 : int config_parse_macsec_sa_activate(
     873                 :            :                 const char *unit,
     874                 :            :                 const char *filename,
     875                 :            :                 unsigned line,
     876                 :            :                 const char *section,
     877                 :            :                 unsigned section_line,
     878                 :            :                 const char *lvalue,
     879                 :            :                 int ltype,
     880                 :            :                 const char *rvalue,
     881                 :            :                 void *data,
     882                 :            :                 void *userdata) {
     883                 :            : 
     884                 :          0 :         _cleanup_(macsec_transmit_association_free_or_set_invalidp) TransmitAssociation *a = NULL;
     885                 :          0 :         _cleanup_(macsec_receive_association_free_or_set_invalidp) ReceiveAssociation *b = NULL;
     886                 :          0 :         MACsec *s = userdata;
     887                 :            :         int *dest;
     888                 :            :         int r;
     889                 :            : 
     890         [ #  # ]:          0 :         assert(filename);
     891         [ #  # ]:          0 :         assert(section);
     892         [ #  # ]:          0 :         assert(lvalue);
     893         [ #  # ]:          0 :         assert(rvalue);
     894         [ #  # ]:          0 :         assert(data);
     895                 :            : 
     896         [ #  # ]:          0 :         if (streq(section, "MACsecTransmitAssociation"))
     897                 :          0 :                 r = macsec_transmit_association_new_static(s, filename, section_line, &a);
     898                 :            :         else
     899                 :          0 :                 r = macsec_receive_association_new_static(s, filename, section_line, &b);
     900         [ #  # ]:          0 :         if (r < 0)
     901                 :          0 :                 return r;
     902                 :            : 
     903         [ #  # ]:          0 :         dest = a ? &a->sa.activate : &b->sa.activate;
     904                 :            : 
     905         [ #  # ]:          0 :         if (isempty(rvalue))
     906                 :          0 :                 r = -1;
     907                 :            :         else {
     908                 :          0 :                 r = parse_boolean(rvalue);
     909         [ #  # ]:          0 :                 if (r < 0) {
     910   [ #  #  #  # ]:          0 :                         log_syntax(unit, LOG_ERR, filename, line, r,
     911                 :            :                                    "Failed to parse activation mode of %s security association. "
     912                 :            :                                    "Ignoring assignment: %s",
     913                 :            :                                    streq(section, "MACsecTransmitAssociation") ? "transmit" : "receive",
     914                 :            :                                    rvalue);
     915                 :          0 :                         return 0;
     916                 :            :                 }
     917                 :            :         }
     918                 :            : 
     919                 :          0 :         *dest = r;
     920                 :          0 :         TAKE_PTR(a);
     921                 :          0 :         TAKE_PTR(b);
     922                 :            : 
     923                 :          0 :         return 0;
     924                 :            : }
     925                 :            : 
     926                 :          0 : int config_parse_macsec_use_for_encoding(
     927                 :            :                 const char *unit,
     928                 :            :                 const char *filename,
     929                 :            :                 unsigned line,
     930                 :            :                 const char *section,
     931                 :            :                 unsigned section_line,
     932                 :            :                 const char *lvalue,
     933                 :            :                 int ltype,
     934                 :            :                 const char *rvalue,
     935                 :            :                 void *data,
     936                 :            :                 void *userdata) {
     937                 :            : 
     938                 :          0 :         _cleanup_(macsec_transmit_association_free_or_set_invalidp) TransmitAssociation *a = NULL;
     939                 :          0 :         MACsec *s = userdata;
     940                 :            :         int r;
     941                 :            : 
     942         [ #  # ]:          0 :         assert(filename);
     943         [ #  # ]:          0 :         assert(section);
     944         [ #  # ]:          0 :         assert(lvalue);
     945         [ #  # ]:          0 :         assert(rvalue);
     946         [ #  # ]:          0 :         assert(data);
     947                 :            : 
     948                 :          0 :         r = macsec_transmit_association_new_static(s, filename, section_line, &a);
     949         [ #  # ]:          0 :         if (r < 0)
     950                 :          0 :                 return r;
     951                 :            : 
     952         [ #  # ]:          0 :         if (isempty(rvalue))
     953                 :          0 :                 r = -1;
     954                 :            :         else {
     955                 :          0 :                 r = parse_boolean(rvalue);
     956         [ #  # ]:          0 :                 if (r < 0) {
     957         [ #  # ]:          0 :                         log_syntax(unit, LOG_ERR, filename, line, r,
     958                 :            :                                    "Failed to parse %s= setting. Ignoring assignment: %s",
     959                 :            :                                    lvalue, rvalue);
     960                 :          0 :                         return 0;
     961                 :            :                 }
     962                 :            :         }
     963                 :            : 
     964                 :          0 :         a->sa.use_for_encoding = r;
     965         [ #  # ]:          0 :         if (a->sa.use_for_encoding > 0)
     966                 :          0 :                 a->sa.activate = true;
     967                 :            : 
     968                 :          0 :         TAKE_PTR(a);
     969                 :            : 
     970                 :          0 :         return 0;
     971                 :            : }
     972                 :            : 
     973                 :          0 : static int macsec_read_key_file(NetDev *netdev, SecurityAssociation *sa) {
     974                 :          0 :         _cleanup_(erase_and_freep) uint8_t *key = NULL;
     975                 :            :         size_t key_len;
     976                 :            :         int r;
     977                 :            : 
     978         [ #  # ]:          0 :         assert(netdev);
     979         [ #  # ]:          0 :         assert(sa);
     980                 :            : 
     981         [ #  # ]:          0 :         if (!sa->key_file)
     982                 :          0 :                 return 0;
     983                 :            : 
     984                 :          0 :         r = read_full_file_full(sa->key_file, READ_FULL_FILE_SECURE | READ_FULL_FILE_UNHEX, (char **) &key, &key_len);
     985         [ #  # ]:          0 :         if (r < 0)
     986         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, r,
     987                 :            :                                               "Failed to read key from '%s', ignoring: %m",
     988                 :            :                                               sa->key_file);
     989                 :            : 
     990         [ #  # ]:          0 :         if (key_len != 16)
     991         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
     992                 :            :                                               "Invalid key length (%zu bytes), ignoring: %m", key_len);
     993                 :            : 
     994                 :          0 :         explicit_bzero_safe(sa->key, sa->key_len);
     995                 :          0 :         free_and_replace(sa->key, key);
     996                 :          0 :         sa->key_len = key_len;
     997                 :            : 
     998                 :          0 :         return 0;
     999                 :            : }
    1000                 :            : 
    1001                 :          0 : static int macsec_receive_channel_verify(ReceiveChannel *c) {
    1002                 :            :         NetDev *netdev;
    1003                 :            :         int r;
    1004                 :            : 
    1005         [ #  # ]:          0 :         assert(c);
    1006         [ #  # ]:          0 :         assert(c->macsec);
    1007                 :            : 
    1008                 :          0 :         netdev = NETDEV(c->macsec);
    1009                 :            : 
    1010         [ #  # ]:          0 :         if (section_is_invalid(c->section))
    1011                 :          0 :                 return -EINVAL;
    1012                 :            : 
    1013         [ #  # ]:          0 :         if (ether_addr_is_null(&c->sci.mac))
    1014         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
    1015                 :            :                                               "%s: MACsec receive channel without MAC address configured. "
    1016                 :            :                                               "Ignoring [MACsecReceiveChannel] section from line %u",
    1017                 :            :                                               c->section->filename, c->section->line);
    1018                 :            : 
    1019         [ #  # ]:          0 :         if (c->sci.port == 0)
    1020         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
    1021                 :            :                                               "%s: MACsec receive channel without port configured. "
    1022                 :            :                                               "Ignoring [MACsecReceiveChannel] section from line %u",
    1023                 :            :                                               c->section->filename, c->section->line);
    1024                 :            : 
    1025                 :          0 :         r = ordered_hashmap_ensure_allocated(&c->macsec->receive_channels, &uint64_hash_ops);
    1026         [ #  # ]:          0 :         if (r < 0)
    1027                 :          0 :                 return log_oom();
    1028                 :            : 
    1029                 :          0 :         r = ordered_hashmap_put(c->macsec->receive_channels, &c->sci.as_uint64, c);
    1030         [ #  # ]:          0 :         if (r == -EEXIST)
    1031         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, r,
    1032                 :            :                                               "%s: Multiple [MACsecReceiveChannel] sections have same SCI, "
    1033                 :            :                                               "Ignoring [MACsecReceiveChannel] section from line %u",
    1034                 :            :                                               c->section->filename, c->section->line);
    1035         [ #  # ]:          0 :         if (r < 0)
    1036         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, r,
    1037                 :            :                                               "%s: Failed to store [MACsecReceiveChannel] section at hashmap, "
    1038                 :            :                                               "Ignoring [MACsecReceiveChannel] section from line %u",
    1039                 :            :                                               c->section->filename, c->section->line);
    1040                 :          0 :         return 0;
    1041                 :            : }
    1042                 :            : 
    1043                 :          0 : static int macsec_transmit_association_verify(TransmitAssociation *t) {
    1044                 :            :         NetDev *netdev;
    1045                 :            :         int r;
    1046                 :            : 
    1047         [ #  # ]:          0 :         assert(t);
    1048         [ #  # ]:          0 :         assert(t->macsec);
    1049                 :            : 
    1050                 :          0 :         netdev = NETDEV(t->macsec);
    1051                 :            : 
    1052         [ #  # ]:          0 :         if (section_is_invalid(t->section))
    1053                 :          0 :                 return -EINVAL;
    1054                 :            : 
    1055         [ #  # ]:          0 :         if (t->sa.packet_number == 0)
    1056         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
    1057                 :            :                                               "%s: MACsec transmit secure association without PacketNumber= configured. "
    1058                 :            :                                               "Ignoring [MACsecTransmitAssociation] section from line %u",
    1059                 :            :                                               t->section->filename, t->section->line);
    1060                 :            : 
    1061                 :          0 :         r = macsec_read_key_file(netdev, &t->sa);
    1062         [ #  # ]:          0 :         if (r < 0)
    1063                 :          0 :                 return r;
    1064                 :            : 
    1065         [ #  # ]:          0 :         if (t->sa.key_len <= 0)
    1066         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
    1067                 :            :                                               "%s: MACsec transmit secure association without key configured. "
    1068                 :            :                                               "Ignoring [MACsecTransmitAssociation] section from line %u",
    1069                 :            :                                               t->section->filename, t->section->line);
    1070                 :            : 
    1071                 :          0 :         return 0;
    1072                 :            : }
    1073                 :            : 
    1074                 :          0 : static int macsec_receive_association_verify(ReceiveAssociation *a) {
    1075                 :            :         ReceiveChannel *c;
    1076                 :            :         NetDev *netdev;
    1077                 :            :         int r;
    1078                 :            : 
    1079         [ #  # ]:          0 :         assert(a);
    1080         [ #  # ]:          0 :         assert(a->macsec);
    1081                 :            : 
    1082                 :          0 :         netdev = NETDEV(a->macsec);
    1083                 :            : 
    1084         [ #  # ]:          0 :         if (section_is_invalid(a->section))
    1085                 :          0 :                 return -EINVAL;
    1086                 :            : 
    1087                 :          0 :         r = macsec_read_key_file(netdev, &a->sa);
    1088         [ #  # ]:          0 :         if (r < 0)
    1089                 :          0 :                 return r;
    1090                 :            : 
    1091         [ #  # ]:          0 :         if (a->sa.key_len <= 0)
    1092         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
    1093                 :            :                                               "%s: MACsec receive secure association without key configured. "
    1094                 :            :                                               "Ignoring [MACsecReceiveAssociation] section from line %u",
    1095                 :            :                                               a->section->filename, a->section->line);
    1096                 :            : 
    1097         [ #  # ]:          0 :         if (ether_addr_is_null(&a->sci.mac))
    1098         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
    1099                 :            :                                               "%s: MACsec receive secure association without MAC address configured. "
    1100                 :            :                                               "Ignoring [MACsecReceiveAssociation] section from line %u",
    1101                 :            :                                               a->section->filename, a->section->line);
    1102                 :            : 
    1103         [ #  # ]:          0 :         if (a->sci.port == 0)
    1104         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
    1105                 :            :                                               "%s: MACsec receive secure association without port configured. "
    1106                 :            :                                               "Ignoring [MACsecReceiveAssociation] section from line %u",
    1107                 :            :                                               a->section->filename, a->section->line);
    1108                 :            : 
    1109                 :          0 :         c = ordered_hashmap_get(a->macsec->receive_channels, &a->sci.as_uint64);
    1110         [ #  # ]:          0 :         if (!c) {
    1111         [ #  # ]:          0 :                 _cleanup_(macsec_receive_channel_freep) ReceiveChannel *new_channel = NULL;
    1112                 :            : 
    1113                 :          0 :                 r = macsec_receive_channel_new(a->macsec, a->sci.as_uint64, &new_channel);
    1114         [ #  # ]:          0 :                 if (r < 0)
    1115                 :          0 :                         return log_oom();
    1116                 :            : 
    1117                 :          0 :                 r = ordered_hashmap_ensure_allocated(&a->macsec->receive_channels, &uint64_hash_ops);
    1118         [ #  # ]:          0 :                 if (r < 0)
    1119                 :          0 :                         return log_oom();
    1120                 :            : 
    1121                 :          0 :                 r = ordered_hashmap_put(a->macsec->receive_channels, &new_channel->sci.as_uint64, new_channel);
    1122         [ #  # ]:          0 :                 if (r < 0)
    1123         [ #  # ]:          0 :                         return log_netdev_error_errno(netdev, r,
    1124                 :            :                                                       "%s: Failed to store receive channel at hashmap, "
    1125                 :            :                                                       "Ignoring [MACsecReceiveAssociation] section from line %u",
    1126                 :            :                                                       a->section->filename, a->section->line);
    1127                 :          0 :                 c = TAKE_PTR(new_channel);
    1128                 :            :         }
    1129         [ #  # ]:          0 :         if (c->n_rxsa >= MACSEC_MAX_ASSOCIATION_NUMBER)
    1130         [ #  # ]:          0 :                 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(ERANGE),
    1131                 :            :                                               "%s: Too many [MACsecReceiveAssociation] sections for the same receive channel, "
    1132                 :            :                                               "Ignoring [MACsecReceiveAssociation] section from line %u",
    1133                 :            :                                               a->section->filename, a->section->line);
    1134                 :            : 
    1135                 :          0 :         a->sa.association_number = c->n_rxsa;
    1136                 :          0 :         c->rxsa[c->n_rxsa++] = a;
    1137                 :            : 
    1138                 :          0 :         return 0;
    1139                 :            : }
    1140                 :            : 
    1141                 :          0 : static int netdev_macsec_verify(NetDev *netdev, const char *filename) {
    1142                 :          0 :         MACsec *v = MACSEC(netdev);
    1143                 :            :         TransmitAssociation *a;
    1144                 :            :         ReceiveAssociation *n;
    1145                 :            :         ReceiveChannel *c;
    1146                 :            :         Iterator i;
    1147                 :            :         uint8_t an, encoding_an;
    1148                 :            :         bool use_for_encoding;
    1149                 :            :         int r;
    1150                 :            : 
    1151         [ #  # ]:          0 :         assert(netdev);
    1152         [ #  # ]:          0 :         assert(v);
    1153         [ #  # ]:          0 :         assert(filename);
    1154                 :            : 
    1155         [ #  # ]:          0 :         ORDERED_HASHMAP_FOREACH(c, v->receive_channels_by_section, i) {
    1156                 :          0 :                 r = macsec_receive_channel_verify(c);
    1157         [ #  # ]:          0 :                 if (r < 0)
    1158                 :          0 :                         macsec_receive_channel_free(c);
    1159                 :            :         }
    1160                 :            : 
    1161                 :          0 :         an = 0;
    1162                 :          0 :         use_for_encoding = false;
    1163                 :          0 :         encoding_an = 0;
    1164         [ #  # ]:          0 :         ORDERED_HASHMAP_FOREACH(a, v->transmit_associations_by_section, i) {
    1165                 :          0 :                 r = macsec_transmit_association_verify(a);
    1166         [ #  # ]:          0 :                 if (r < 0) {
    1167                 :          0 :                         macsec_transmit_association_free(a);
    1168                 :          0 :                         continue;
    1169                 :            :                 }
    1170                 :            : 
    1171         [ #  # ]:          0 :                 if (an >= MACSEC_MAX_ASSOCIATION_NUMBER) {
    1172         [ #  # ]:          0 :                         log_netdev_error(netdev,
    1173                 :            :                                          "%s: Too many [MACsecTransmitAssociation] sections configured. "
    1174                 :            :                                          "Ignoring [MACsecTransmitAssociation] section from line %u",
    1175                 :            :                                          a->section->filename, a->section->line);
    1176                 :          0 :                         macsec_transmit_association_free(a);
    1177                 :          0 :                         continue;
    1178                 :            :                 }
    1179                 :            : 
    1180                 :          0 :                 a->sa.association_number = an++;
    1181                 :            : 
    1182         [ #  # ]:          0 :                 if (a->sa.use_for_encoding > 0) {
    1183         [ #  # ]:          0 :                         if (use_for_encoding) {
    1184         [ #  # ]:          0 :                                 log_netdev_warning(netdev,
    1185                 :            :                                                    "%s: Multiple security associations are set to be used for transmit channel."
    1186                 :            :                                                    "Disabling UseForEncoding= in [MACsecTransmitAssociation] section from line %u",
    1187                 :            :                                                    a->section->filename, a->section->line);
    1188                 :          0 :                                 a->sa.use_for_encoding = false;
    1189                 :            :                         } else {
    1190                 :          0 :                                 encoding_an = a->sa.association_number;
    1191                 :          0 :                                 use_for_encoding = true;
    1192                 :            :                         }
    1193                 :            :                 }
    1194                 :            :         }
    1195                 :            : 
    1196         [ #  # ]:          0 :         assert(encoding_an < MACSEC_MAX_ASSOCIATION_NUMBER);
    1197                 :          0 :         v->encoding_an = encoding_an;
    1198                 :            : 
    1199         [ #  # ]:          0 :         ORDERED_HASHMAP_FOREACH(n, v->receive_associations_by_section, i) {
    1200                 :          0 :                 r = macsec_receive_association_verify(n);
    1201         [ #  # ]:          0 :                 if (r < 0)
    1202                 :          0 :                         macsec_receive_association_free(n);
    1203                 :            :         }
    1204                 :            : 
    1205                 :          0 :         return 0;
    1206                 :            : }
    1207                 :            : 
    1208                 :          0 : static void macsec_init(NetDev *netdev) {
    1209                 :            :         MACsec *v;
    1210                 :            : 
    1211         [ #  # ]:          0 :         assert(netdev);
    1212                 :            : 
    1213                 :          0 :         v = MACSEC(netdev);
    1214                 :            : 
    1215         [ #  # ]:          0 :         assert(v);
    1216                 :            : 
    1217                 :          0 :         v->encrypt = -1;
    1218                 :          0 : }
    1219                 :            : 
    1220                 :          0 : static void macsec_done(NetDev *netdev) {
    1221                 :            :         MACsec *t;
    1222                 :            : 
    1223         [ #  # ]:          0 :         assert(netdev);
    1224                 :            : 
    1225                 :          0 :         t = MACSEC(netdev);
    1226                 :            : 
    1227         [ #  # ]:          0 :         assert(t);
    1228                 :            : 
    1229         [ #  # ]:          0 :         ordered_hashmap_free_with_destructor(t->receive_channels, macsec_receive_channel_free);
    1230         [ #  # ]:          0 :         ordered_hashmap_free_with_destructor(t->receive_channels_by_section, macsec_receive_channel_free);
    1231         [ #  # ]:          0 :         ordered_hashmap_free_with_destructor(t->transmit_associations_by_section, macsec_transmit_association_free);
    1232         [ #  # ]:          0 :         ordered_hashmap_free_with_destructor(t->receive_associations_by_section, macsec_receive_association_free);
    1233                 :          0 : }
    1234                 :            : 
    1235                 :            : const NetDevVTable macsec_vtable = {
    1236                 :            :         .object_size = sizeof(MACsec),
    1237                 :            :         .init = macsec_init,
    1238                 :            :         .sections = "Match\0NetDev\0MACsec\0MACsecReceiveChannel\0MACsecTransmitAssociation\0MACsecReceiveAssociation\0",
    1239                 :            :         .fill_message_create = netdev_macsec_fill_message_create,
    1240                 :            :         .post_create = netdev_macsec_configure,
    1241                 :            :         .done = macsec_done,
    1242                 :            :         .create_type = NETDEV_CREATE_STACKED,
    1243                 :            :         .config_verify = netdev_macsec_verify,
    1244                 :            :         .generate_mac = true,
    1245                 :            : };

Generated by: LCOV version 1.14