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 : : };
|