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