LCOV - code coverage report
Current view: top level - network/netdev - macsec.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 0 650 0.0 %
Date: 2019-08-22 15:41:25 Functions: 0 45 0.0 %

          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