diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index bb6c35f9ba..9468a548f6 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -2350,7 +2350,7 @@
BitRate=
The bitrate of CAN device in bits per second. The usual SI prefixes (K, M) with the base of 1000 can
- be used here.
+ be used here. Takes a number in the range 1..4294967295.
@@ -2360,6 +2360,29 @@
87.5%) or permille (e.g. 875‰).
+
+ DataBitRate=
+ DataSamplePoint=
+
+ The bitrate and sample point for the data phase, if CAN-FD is used. These settings are
+ analogous to the BitRate= and SamplePoint= keys.
+
+
+
+ FDMode=
+
+ Takes a boolean. When yes, CAN-FD mode is enabled for the interface.
+ Note, that a bitrate and optional sample point should also be set for the CAN-FD data phase using
+ the DataBitRate= and DataSamplePoint= keys.
+
+
+
+ FDNonISO=
+
+ Takes a boolean. When yes, non-ISO CAN-FD mode is enabled for the
+ interface. When unset, the kernel's default will be used.
+
+
RestartSec=
diff --git a/src/network/networkd-can.c b/src/network/networkd-can.c
index 18533843e3..fdd99a3a18 100644
--- a/src/network/networkd-can.c
+++ b/src/network/networkd-can.c
@@ -7,10 +7,51 @@
#include "networkd-can.h"
#include "networkd-link.h"
#include "networkd-manager.h"
+#include "parse-util.h"
#include "string-util.h"
#define CAN_TERMINATION_OHM_VALUE 120
+int config_parse_can_bitrate(
+ const char* unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ uint32_t *br = data;
+ uint64_t sz;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = parse_size(rvalue, 1000, &sz);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to parse can bitrate '%s', ignoring: %m", rvalue);
+ return 0;
+ }
+
+ /* Linux uses __u32 for bitrates, so the value should not exceed that. */
+ if (sz <= 0 || sz > UINT32_MAX) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "Bit rate out of permitted range 1...4294967295");
+ return 0;
+ }
+
+ *br = (uint32_t) sz;
+
+ return 0;
+}
+
static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
@@ -103,11 +144,6 @@ static int link_set_can(Link *link) {
.sample_point = link->network->can_sample_point,
};
- if (link->network->can_bitrate > UINT32_MAX) {
- log_link_error(link, "bitrate (%" PRIu64 ") too big.", link->network->can_bitrate);
- return -ERANGE;
- }
-
log_link_debug(link, "Setting bitrate = %d bit/s", bt.bitrate);
if (link->network->can_sample_point > 0)
log_link_debug(link, "Setting sample point = %d.%d%%", bt.sample_point / 10, bt.sample_point % 10);
@@ -119,6 +155,35 @@ static int link_set_can(Link *link) {
return log_link_error_errno(link, r, "Could not append IFLA_CAN_BITTIMING attribute: %m");
}
+ if (link->network->can_data_bitrate > 0 || link->network->can_data_sample_point > 0) {
+ struct can_bittiming bt = {
+ .bitrate = link->network->can_data_bitrate,
+ .sample_point = link->network->can_data_sample_point,
+ };
+
+ log_link_debug(link, "Setting data bitrate = %d bit/s", bt.bitrate);
+ if (link->network->can_data_sample_point > 0)
+ log_link_debug(link, "Setting data sample point = %d.%d%%", bt.sample_point / 10, bt.sample_point % 10);
+ else
+ log_link_debug(link, "Using default data sample point");
+
+ r = sd_netlink_message_append_data(m, IFLA_CAN_DATA_BITTIMING, &bt, sizeof(bt));
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append IFLA_CAN_DATA_BITTIMING attribute: %m");
+ }
+
+ if (link->network->can_fd_mode >= 0) {
+ cm.mask |= CAN_CTRLMODE_FD;
+ SET_FLAG(cm.flags, CAN_CTRLMODE_FD, link->network->can_fd_mode > 0);
+ log_link_debug(link, "%sabling FD mode", link->network->can_fd_mode > 0 ? "En" : "Dis");
+ }
+
+ if (link->network->can_non_iso >= 0) {
+ cm.mask |= CAN_CTRLMODE_FD_NON_ISO;
+ SET_FLAG(cm.flags, CAN_CTRLMODE_FD_NON_ISO, link->network->can_non_iso > 0);
+ log_link_debug(link, "%sabling FD non-ISO mode", link->network->can_non_iso > 0 ? "En" : "Dis");
+ }
+
if (link->network->can_restart_us > 0) {
char time_string[FORMAT_TIMESPAN_MAX];
uint64_t restart_ms;
diff --git a/src/network/networkd-can.h b/src/network/networkd-can.h
index c744bdfea7..30e99b189d 100644
--- a/src/network/networkd-can.h
+++ b/src/network/networkd-can.h
@@ -1,6 +1,10 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
+#include "conf-parser.h"
+
typedef struct Link Link;
int link_configure_can(Link *link);
+
+CONFIG_PARSER_PROTOTYPE(config_parse_can_bitrate);
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 18ba23bfc8..7833eec1cf 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -6,6 +6,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
#include "conf-parser.h"
#include "netem.h"
#include "network-internal.h"
+#include "networkd-can.h"
#include "networkd-conf.h"
#include "networkd-dhcp-common.h"
#include "networkd-dhcp-server.h"
@@ -257,8 +258,12 @@ IPv6Prefix.PreferredLifetimeSec, config_parse_prefix_lifetime,
IPv6Prefix.Assign, config_parse_prefix_assign, 0, 0
IPv6RoutePrefix.Route, config_parse_route_prefix, 0, 0
IPv6RoutePrefix.LifetimeSec, config_parse_route_prefix_lifetime, 0, 0
-CAN.BitRate, config_parse_si_uint64, 0, offsetof(Network, can_bitrate)
+CAN.BitRate, config_parse_can_bitrate, 0, offsetof(Network, can_bitrate)
CAN.SamplePoint, config_parse_permille, 0, offsetof(Network, can_sample_point)
+CAN.DataBitRate, config_parse_can_bitrate, 0, offsetof(Network, can_data_bitrate)
+CAN.DataSamplePoint, config_parse_permille, 0, offsetof(Network, can_data_sample_point)
+CAN.FDMode, config_parse_tristate, 0, offsetof(Network, can_fd_mode)
+CAN.FDNonISO, config_parse_tristate, 0, offsetof(Network, can_non_iso)
CAN.RestartSec, config_parse_sec, 0, offsetof(Network, can_restart_us)
CAN.TripleSampling, config_parse_tristate, 0, offsetof(Network, can_triple_sampling)
CAN.Termination, config_parse_tristate, 0, offsetof(Network, can_termination)
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index 66ee01d7f3..8bd380c6a8 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -205,12 +205,16 @@ struct Network {
uint32_t br_untagged_bitmap[BRIDGE_VLAN_BITMAP_LEN];
/* CAN support */
- uint64_t can_bitrate;
+ uint32_t can_bitrate;
unsigned can_sample_point;
+ uint32_t can_data_bitrate;
+ unsigned can_data_sample_point;
usec_t can_restart_us;
int can_triple_sampling;
int can_termination;
int can_listen_only;
+ int can_fd_mode;
+ int can_non_iso;
AddressFamily ip_forward;
bool ip_masquerade;
diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network
index 01b1b50ff6..fe70429ffe 100644
--- a/test/fuzz/fuzz-network-parser/directives.network
+++ b/test/fuzz/fuzz-network-parser/directives.network
@@ -201,6 +201,10 @@ PVID=
[CAN]
SamplePoint=
BitRate=
+DataSamplePoint=
+DataBitRate=
+FDMode=
+FDNonISO=
RestartSec=
TripleSampling=
Termination=