1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <net/if.h>
4 #include <linux/can/netlink.h>
5
6 #include "networkd-can.h"
7 #include "networkd-link.h"
8 #include "networkd-network.h"
9 #include "networkd-setlink.h"
10 #include "parse-util.h"
11 #include "string-util.h"
12
13 #define CAN_TERMINATION_DEFAULT_OHM_VALUE 120
14
can_set_netlink_message(Link * link,sd_netlink_message * m)15 int can_set_netlink_message(Link *link, sd_netlink_message *m) {
16 int r;
17
18 assert(link);
19 assert(link->network);
20 assert(m);
21
22 r = sd_netlink_message_set_flags(m, NLM_F_REQUEST | NLM_F_ACK);
23 if (r < 0)
24 return r;
25
26 r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
27 if (r < 0)
28 return r;
29
30 r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, link->kind);
31 if (r < 0)
32 return r;
33
34 if (link->network->can_bitrate > 0) {
35 struct can_bittiming bt = {
36 .bitrate = link->network->can_bitrate,
37 .sample_point = link->network->can_sample_point,
38 .sjw = link->network->can_sync_jump_width,
39 };
40
41 log_link_debug(link, "Setting bitrate = %d bit/s", bt.bitrate);
42 if (link->network->can_sample_point > 0)
43 log_link_debug(link, "Setting sample point = %d.%d%%", bt.sample_point / 10, bt.sample_point % 10);
44 else
45 log_link_debug(link, "Using default sample point");
46
47 r = sd_netlink_message_append_data(m, IFLA_CAN_BITTIMING, &bt, sizeof(bt));
48 if (r < 0)
49 return r;
50 } else if (link->network->can_time_quanta_ns > 0) {
51 struct can_bittiming bt = {
52 .tq = link->network->can_time_quanta_ns,
53 .prop_seg = link->network->can_propagation_segment,
54 .phase_seg1 = link->network->can_phase_buffer_segment_1,
55 .phase_seg2 = link->network->can_phase_buffer_segment_2,
56 .sjw = link->network->can_sync_jump_width,
57 };
58
59 log_link_debug(link, "Setting time quanta = %"PRIu32" nsec", bt.tq);
60 r = sd_netlink_message_append_data(m, IFLA_CAN_BITTIMING, &bt, sizeof(bt));
61 if (r < 0)
62 return r;
63 }
64
65 if (link->network->can_data_bitrate > 0) {
66 struct can_bittiming bt = {
67 .bitrate = link->network->can_data_bitrate,
68 .sample_point = link->network->can_data_sample_point,
69 .sjw = link->network->can_data_sync_jump_width,
70 };
71
72 log_link_debug(link, "Setting data bitrate = %d bit/s", bt.bitrate);
73 if (link->network->can_data_sample_point > 0)
74 log_link_debug(link, "Setting data sample point = %d.%d%%", bt.sample_point / 10, bt.sample_point % 10);
75 else
76 log_link_debug(link, "Using default data sample point");
77
78 r = sd_netlink_message_append_data(m, IFLA_CAN_DATA_BITTIMING, &bt, sizeof(bt));
79 if (r < 0)
80 return r;
81 } else if (link->network->can_data_time_quanta_ns > 0) {
82 struct can_bittiming bt = {
83 .tq = link->network->can_data_time_quanta_ns,
84 .prop_seg = link->network->can_data_propagation_segment,
85 .phase_seg1 = link->network->can_data_phase_buffer_segment_1,
86 .phase_seg2 = link->network->can_data_phase_buffer_segment_2,
87 .sjw = link->network->can_data_sync_jump_width,
88 };
89
90 log_link_debug(link, "Setting data time quanta = %"PRIu32" nsec", bt.tq);
91 r = sd_netlink_message_append_data(m, IFLA_CAN_DATA_BITTIMING, &bt, sizeof(bt));
92 if (r < 0)
93 return r;
94 }
95
96 if (link->network->can_restart_us > 0) {
97 uint64_t restart_ms;
98
99 if (link->network->can_restart_us == USEC_INFINITY)
100 restart_ms = 0;
101 else
102 restart_ms = DIV_ROUND_UP(link->network->can_restart_us, USEC_PER_MSEC);
103
104 log_link_debug(link, "Setting restart = %s", FORMAT_TIMESPAN(restart_ms * 1000, MSEC_PER_SEC));
105 r = sd_netlink_message_append_u32(m, IFLA_CAN_RESTART_MS, restart_ms);
106 if (r < 0)
107 return r;
108 }
109
110 if (link->network->can_control_mode_mask != 0) {
111 struct can_ctrlmode cm = {
112 .mask = link->network->can_control_mode_mask,
113 .flags = link->network->can_control_mode_flags,
114 };
115
116 r = sd_netlink_message_append_data(m, IFLA_CAN_CTRLMODE, &cm, sizeof(cm));
117 if (r < 0)
118 return r;
119 }
120
121 if (link->network->can_termination_set) {
122 log_link_debug(link, "Setting can-termination to '%u'.", link->network->can_termination);
123
124 r = sd_netlink_message_append_u16(m, IFLA_CAN_TERMINATION, link->network->can_termination);
125 if (r < 0)
126 return r;
127 }
128
129 r = sd_netlink_message_close_container(m);
130 if (r < 0)
131 return r;
132
133 r = sd_netlink_message_close_container(m);
134 if (r < 0)
135 return r;
136
137 return 0;
138 }
139
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)140 int config_parse_can_bitrate(
141 const char* unit,
142 const char *filename,
143 unsigned line,
144 const char *section,
145 unsigned section_line,
146 const char *lvalue,
147 int ltype,
148 const char *rvalue,
149 void *data,
150 void *userdata) {
151
152 uint32_t *br = data;
153 uint64_t sz;
154 int r;
155
156 assert(filename);
157 assert(lvalue);
158 assert(rvalue);
159 assert(data);
160
161 r = parse_size(rvalue, 1000, &sz);
162 if (r < 0) {
163 log_syntax(unit, LOG_WARNING, filename, line, r,
164 "Failed to parse can bitrate '%s', ignoring: %m", rvalue);
165 return 0;
166 }
167
168 /* Linux uses __u32 for bitrates, so the value should not exceed that. */
169 if (sz <= 0 || sz > UINT32_MAX) {
170 log_syntax(unit, LOG_WARNING, filename, line, 0,
171 "Bit rate out of permitted range 1...4294967295");
172 return 0;
173 }
174
175 *br = (uint32_t) sz;
176
177 return 0;
178 }
179
config_parse_can_time_quanta(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)180 int config_parse_can_time_quanta(
181 const char* unit,
182 const char *filename,
183 unsigned line,
184 const char *section,
185 unsigned section_line,
186 const char *lvalue,
187 int ltype,
188 const char *rvalue,
189 void *data,
190 void *userdata) {
191
192 nsec_t val, *tq = data;
193 int r;
194
195 assert(filename);
196 assert(lvalue);
197 assert(rvalue);
198 assert(data);
199
200 r = parse_nsec(rvalue, &val);
201 if (r < 0) {
202 log_syntax(unit, LOG_WARNING, filename, line, r,
203 "Failed to parse can time quanta '%s', ignoring: %m", rvalue);
204 return 0;
205 }
206
207 /* Linux uses __u32 for bitrates, so the value should not exceed that. */
208 if (val <= 0 || val > UINT32_MAX) {
209 log_syntax(unit, LOG_WARNING, filename, line, 0,
210 "Time quanta out of permitted range 1...4294967295");
211 return 0;
212 }
213
214 *tq = val;
215 return 0;
216 }
217
config_parse_can_restart_usec(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)218 int config_parse_can_restart_usec(
219 const char* unit,
220 const char *filename,
221 unsigned line,
222 const char *section,
223 unsigned section_line,
224 const char *lvalue,
225 int ltype,
226 const char *rvalue,
227 void *data,
228 void *userdata) {
229
230 usec_t usec, *restart_usec = data;
231 int r;
232
233 assert(filename);
234 assert(lvalue);
235 assert(rvalue);
236 assert(data);
237
238 r = parse_sec(rvalue, &usec);
239 if (r < 0) {
240 log_syntax(unit, LOG_WARNING, filename, line, r,
241 "Failed to parse CAN restart sec '%s', ignoring: %m", rvalue);
242 return 0;
243 }
244
245 if (usec != USEC_INFINITY &&
246 DIV_ROUND_UP(usec, USEC_PER_MSEC) > UINT32_MAX) {
247 log_syntax(unit, LOG_WARNING, filename, line, 0,
248 "CAN RestartSec= must be in the range 0...%"PRIu32"ms, ignoring: %s", UINT32_MAX, rvalue);
249 return 0;
250 }
251
252 *restart_usec = usec;
253 return 0;
254 }
255
config_parse_can_control_mode(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)256 int config_parse_can_control_mode(
257 const char* unit,
258 const char *filename,
259 unsigned line,
260 const char *section,
261 unsigned section_line,
262 const char *lvalue,
263 int ltype,
264 const char *rvalue,
265 void *data,
266 void *userdata) {
267
268 Network *network = userdata;
269 uint32_t mask = ltype;
270 int r;
271
272 assert(filename);
273 assert(lvalue);
274 assert(rvalue);
275 assert(userdata);
276 assert(mask != 0);
277
278 if (isempty(rvalue)) {
279 network->can_control_mode_mask &= ~mask;
280 network->can_control_mode_flags &= ~mask;
281 return 0;
282 }
283
284 r = parse_boolean(rvalue);
285 if (r < 0) {
286 log_syntax(unit, LOG_WARNING, filename, line, r,
287 "Failed to parse CAN control mode '%s', ignoring: %s", lvalue, rvalue);
288 return 0;
289 }
290
291 network->can_control_mode_mask |= mask;
292 SET_FLAG(network->can_control_mode_flags, mask, r);
293 return 0;
294 }
295
config_parse_can_termination(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)296 int config_parse_can_termination(
297 const char* unit,
298 const char *filename,
299 unsigned line,
300 const char *section,
301 unsigned section_line,
302 const char *lvalue,
303 int ltype,
304 const char *rvalue,
305 void *data,
306 void *userdata) {
307
308 Network *network = userdata;
309 int r;
310
311 assert(filename);
312 assert(lvalue);
313 assert(rvalue);
314 assert(data);
315
316 if (isempty(rvalue)) {
317 network->can_termination_set = false;
318 return 0;
319 }
320
321 /* Note that 0 termination ohm value means no termination resistor, and there is no conflict
322 * between parse_boolean() and safe_atou16() when Termination=0. However, Termination=1 must be
323 * treated as 1 ohm, instead of true (and then the default ohm value). So, we need to parse the
324 * string with safe_atou16() at first. */
325
326 r = safe_atou16(rvalue, &network->can_termination);
327 if (r < 0) {
328 r = parse_boolean(rvalue);
329 if (r < 0) {
330 log_syntax(unit, LOG_WARNING, filename, line, r,
331 "Failed to parse CAN termination value, ignoring: %s", rvalue);
332 return 0;
333 }
334
335 network->can_termination = r ? CAN_TERMINATION_DEFAULT_OHM_VALUE : 0;
336 }
337
338 network->can_termination_set = true;
339 return 0;
340 }
341