diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index bb6c35f9ba..be0756513f 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.
diff --git a/src/network/networkd-can.c b/src/network/networkd-can.c
index 18533843e3..4118fcf859 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);
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..ee50da098d 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,7 +258,7 @@ 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.RestartSec, config_parse_sec, 0, offsetof(Network, can_restart_us)
CAN.TripleSampling, config_parse_tristate, 0, offsetof(Network, can_triple_sampling)
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index 66ee01d7f3..7acb4a5461 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -205,7 +205,7 @@ 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;
usec_t can_restart_us;
int can_triple_sampling;