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