Skip to content

Commit f549614

Browse files
martinjaegernashif
authored andcommitted
canbus: isotp: allow frames with padding
ISO 15765-2 specifies that the CAN frame length for single frames and the last consecutive frame may or may not be optimized to the actual length of the PDU payload. The ISO-TP implementation should only consider the information from the N_PCI section. The previous implementation did not allow padding. With this commit, padding is allowed by default and can even be required to be more compliant to AUTOSAR standards. Signed-off-by: Martin Jäger <[email protected]>
1 parent ade6cc4 commit f549614

File tree

3 files changed

+114
-24
lines changed

3 files changed

+114
-24
lines changed

subsys/canbus/isotp/Kconfig

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,22 @@ config ISOTP_CR_TIMEOUT
4747
Cr (receiver consecutive frame) timeout.
4848
ISO 15765-2: 1000ms
4949

50+
config ISOTP_REQUIRE_RX_PADDING
51+
bool "Require padding for received messages"
52+
help
53+
If enabled, SFs and the last CF must always have a DLC of 8 bytes
54+
(for classic CAN) and unused bytes must be padded by the sending
55+
device. This setting allows to be compliant to AUTOSAR Specification
56+
of CAN Transport Layer.
57+
58+
By default, received CAN frames with or without padding are accepted.
59+
60+
config ISOTP_ENABLE_TX_PADDING
61+
bool "Enable padding for transmitted messages"
62+
help
63+
Add padding bytes 0xCC (as recommended by Bosch) if the PDU payload
64+
does not fit exactly into the CAN frame.
65+
5066
config ISOTP_WORKQUEUE_PRIO
5167
int "Priority level of the RX and TX work queue"
5268
default 2

subsys/canbus/isotp/isotp.c

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ static void receive_send_fc(struct isotp_recv_ctx *ctx, uint8_t fs)
136136
.id = ctx->tx_addr.ext_id
137137
};
138138
uint8_t *data = frame.data;
139+
uint8_t payload_len;
139140
int ret;
140141

141142
__ASSERT_NO_MSG(!(fs & ISOTP_PCI_TYPE_MASK));
@@ -147,7 +148,16 @@ static void receive_send_fc(struct isotp_recv_ctx *ctx, uint8_t fs)
147148
*data++ = ISOTP_PCI_TYPE_FC | fs;
148149
*data++ = ctx->opts.bs;
149150
*data++ = ctx->opts.stmin;
150-
frame.dlc = data - frame.data;
151+
payload_len = data - frame.data;
152+
153+
#if defined(CONFIG_ISOTP_REQUIRE_RX_PADDING) || \
154+
defined(CONFIG_ISOTP_ENABLE_TX_PADDING)
155+
/* AUTOSAR requirement SWS_CanTp_00347 */
156+
memset(&frame.data[payload_len], 0xCC, ISOTP_CAN_DL - payload_len);
157+
frame.dlc = ISOTP_CAN_DL;
158+
#else
159+
frame.dlc = payload_len;
160+
#endif
151161

152162
ret = can_send(ctx->can_dev, &frame, K_MSEC(ISOTP_A),
153163
receive_can_tx_isr, ctx);
@@ -264,10 +274,10 @@ static void receive_state_machine(struct isotp_recv_ctx *ctx)
264274

265275
switch (ctx->state) {
266276
case ISOTP_RX_STATE_PROCESS_SF:
267-
ctx->buf->len = receive_get_sf_length(ctx->buf);
277+
ctx->length = receive_get_sf_length(ctx->buf);
268278
ud_rem_len = net_buf_user_data(ctx->buf);
269279
*ud_rem_len = 0;
270-
LOG_DBG("SM process SF of length %d", ctx->buf->len);
280+
LOG_DBG("SM process SF of length %d", ctx->length);
271281
net_buf_put(&ctx->fifo, ctx->buf);
272282
ctx->state = ISOTP_RX_STATE_RECYCLE;
273283
receive_state_machine(ctx);
@@ -380,6 +390,7 @@ static void receive_work_handler(struct k_work *item)
380390
static void process_ff_sf(struct isotp_recv_ctx *ctx, struct zcan_frame *frame)
381391
{
382392
int index = 0;
393+
uint8_t payload_len;
383394

384395
if (ctx->rx_addr.use_ext_addr) {
385396
if (frame->data[index++] != ctx->rx_addr.ext_addr) {
@@ -391,19 +402,30 @@ static void process_ff_sf(struct isotp_recv_ctx *ctx, struct zcan_frame *frame)
391402
case ISOTP_PCI_TYPE_FF:
392403
LOG_DBG("Got FF IRQ");
393404
if (frame->dlc != ISOTP_CAN_DL) {
394-
LOG_INF("FF DL does not match. Ignore");
405+
LOG_INF("FF DLC invalid. Ignore");
395406
return;
396407
}
397408

409+
payload_len = ISOTP_CAN_DL;
398410
ctx->state = ISOTP_RX_STATE_PROCESS_FF;
399411
ctx->sn_expected = 1;
400412
break;
401413

402414
case ISOTP_PCI_TYPE_SF:
403415
LOG_DBG("Got SF IRQ");
404-
if ((frame->data[index] & ISOTP_PCI_FF_DL_UPPER_MASK) +
405-
index + 1 != frame->dlc) {
406-
LOG_INF("SF DL does not match. Ignore");
416+
#ifdef CONFIG_ISOTP_REQUIRE_RX_PADDING
417+
/* AUTOSAR requirement SWS_CanTp_00345 */
418+
if (frame->dlc != ISOTP_CAN_DL) {
419+
LOG_INF("SF DLC invalid. Ignore");
420+
return;
421+
}
422+
#endif
423+
424+
payload_len = index + 1 + (frame->data[index] &
425+
ISOTP_PCI_SF_DL_MASK);
426+
427+
if (payload_len > frame->dlc) {
428+
LOG_INF("SF DL does not fit. Ignore");
407429
return;
408430
}
409431

@@ -415,7 +437,7 @@ static void process_ff_sf(struct isotp_recv_ctx *ctx, struct zcan_frame *frame)
415437
return;
416438
}
417439

418-
net_buf_add_mem(ctx->buf, &frame->data[index], frame->dlc - index);
440+
net_buf_add_mem(ctx->buf, &frame->data[index], payload_len - index);
419441
}
420442

421443
static inline void receive_add_mem(struct isotp_recv_ctx *ctx, uint8_t *data,
@@ -432,7 +454,7 @@ static inline void receive_add_mem(struct isotp_recv_ctx *ctx, uint8_t *data,
432454
net_buf_add_mem(ctx->act_frag, data, tailroom);
433455
ctx->act_frag = ctx->act_frag->frags;
434456
if (!ctx->act_frag) {
435-
LOG_ERR("No fragmet left to append data");
457+
LOG_ERR("No fragment left to append data");
436458
receive_report_error(ctx, ISOTP_N_BUFFER_OVERFLW);
437459
return;
438460
}
@@ -444,6 +466,7 @@ static void process_cf(struct isotp_recv_ctx *ctx, struct zcan_frame *frame)
444466
{
445467
uint32_t *ud_rem_len = (uint32_t *)net_buf_user_data(ctx->buf);
446468
int index = 0;
469+
uint32_t data_len;
447470

448471
if (ctx->rx_addr.use_ext_addr) {
449472
if (frame->data[index++] != ctx->rx_addr.ext_addr) {
@@ -470,14 +493,20 @@ static void process_cf(struct isotp_recv_ctx *ctx, struct zcan_frame *frame)
470493
return;
471494
}
472495

473-
if (frame->dlc - index > ctx->length) {
474-
LOG_ERR("The frame contains more bytes than expected");
496+
#ifdef CONFIG_ISOTP_REQUIRE_RX_PADDING
497+
/* AUTOSAR requirement SWS_CanTp_00346 */
498+
if (frame->dlc != ISOTP_CAN_DL) {
499+
LOG_ERR("CF DL invalid");
475500
receive_report_error(ctx, ISOTP_N_ERROR);
501+
return;
476502
}
503+
#endif
477504

478505
LOG_DBG("Got CF irq. Appending data");
479-
receive_add_mem(ctx, &frame->data[index], frame->dlc - index);
480-
ctx->length -= frame->dlc - index;
506+
data_len = (ctx->length > frame->dlc - index) ? frame->dlc - index :
507+
ctx->length;
508+
receive_add_mem(ctx, &frame->data[index], data_len);
509+
ctx->length -= data_len;
481510
LOG_DBG("%d bytes remaining", ctx->length);
482511

483512
if (ctx->length == 0) {
@@ -755,6 +784,15 @@ static void send_process_fc(struct isotp_send_ctx *ctx,
755784
return;
756785
}
757786

787+
#ifdef CONFIG_ISOTP_ENABLE_TX_PADDING
788+
/* AUTOSAR requirement SWS_CanTp_00349 */
789+
if (frame->dlc != ISOTP_CAN_DL) {
790+
LOG_ERR("FC DL invalid. Ignore");
791+
send_report_error(ctx, ISOTP_N_ERROR);
792+
return;
793+
}
794+
#endif
795+
758796
switch (*data++ & ISOTP_PCI_FS_MASK) {
759797
case ISOTP_PCI_FS_CTS:
760798
ctx->state = ISOTP_TX_SEND_CF;
@@ -853,7 +891,13 @@ static inline int send_sf(struct isotp_send_ctx *ctx)
853891
__ASSERT_NO_MSG(len <= ISOTP_CAN_DL - index);
854892
memcpy(&frame.data[index], data, len);
855893

894+
#ifdef CONFIG_ISOTP_ENABLE_TX_PADDING
895+
/* AUTOSAR requirement SWS_CanTp_00348 */
896+
memset(&frame.data[index + len], 0xCC, ISOTP_CAN_DL - len - index);
897+
frame.dlc = ISOTP_CAN_DL;
898+
#else
856899
frame.dlc = len + index;
900+
#endif
857901

858902
ctx->state = ISOTP_TX_SEND_SF;
859903
ret = can_send(ctx->can_dev, &frame, K_MSEC(ISOTP_A),
@@ -926,10 +970,17 @@ static inline int send_cf(struct isotp_send_ctx *ctx)
926970
rem_len = get_ctx_data_length(ctx);
927971
len = MIN(rem_len, ISOTP_CAN_DL - index);
928972
rem_len -= len;
929-
frame.dlc = len + index;
930973
data = get_data_ctx(ctx);
931974
memcpy(&frame.data[index], data, len);
932975

976+
#ifdef CONFIG_ISOTP_ENABLE_TX_PADDING
977+
/* AUTOSAR requirement SWS_CanTp_00348 */
978+
memset(&frame.data[index + len], 0xCC, ISOTP_CAN_DL - len - index);
979+
frame.dlc = ISOTP_CAN_DL;
980+
#else
981+
frame.dlc = len + index;
982+
#endif
983+
933984
ret = can_send(ctx->can_dev, &frame, K_MSEC(ISOTP_A),
934985
send_can_tx_isr, ctx);
935986
if (ret == CAN_TX_OK) {

tests/subsys/canbus/isotp/conformance/src/main.c

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,19 @@
3131
#define FC_PCI_BYTE_1(FS) ((FC_PCI_TYPE << PCI_TYPE_POS) | (FS))
3232
#define FC_PCI_BYTE_2(BS) (BS)
3333
#define FC_PCI_BYTE_3(ST_MIN) (ST_MIN)
34-
#define DATA_SIZE_FC 3
3534
#define CF_PCI_TYPE 2
3635
#define CF_PCI_BYTE_1 (CF_PCI_TYPE << PCI_TYPE_POS)
3736
#define STMIN_VAL_1 5
3837
#define STMIN_VAL_2 50
3938
#define STMIN_UPPER_TOLERANCE 5
4039

40+
#if defined(CONFIG_ISOTP_ENABLE_TX_PADDING) || \
41+
defined(CONFIG_ISOTP_ENABLE_TX_PADDING)
42+
#define DATA_SIZE_FC CAN_DL
43+
#else
44+
#define DATA_SIZE_FC 3
45+
#endif
46+
4147
#define CEIL(A, B) (((A) + (B) - 1) / (B))
4248

4349
#define BS_TIMEOUT_UPPER_MS 1100
@@ -167,6 +173,8 @@ static void get_sf(struct isotp_recv_ctx *recv_ctx, size_t data_size)
167173
zassert_equal(ret, 0, "Data differ");
168174
}
169175

176+
#ifdef CONFIG_ISOTP_REQUIRE_RX_PADDING
177+
170178
static void get_sf_ignore(struct isotp_recv_ctx *recv_ctx)
171179
{
172180
int ret;
@@ -175,6 +183,8 @@ static void get_sf_ignore(struct isotp_recv_ctx *recv_ctx)
175183
zassert_equal(ret, ISOTP_RECV_TIMEOUT, "recv returned %d", ret);
176184
}
177185

186+
#endif
187+
178188
static void send_test_data(const uint8_t *data, size_t len)
179189
{
180190
int ret;
@@ -246,11 +256,18 @@ static void check_frame_series(struct frame_desired *frames, size_t length,
246256
zassert_equal(ret, 0, "Timeout waiting for msg nr %d. ret: %d",
247257
i, ret);
248258

259+
#if !defined(CONFIG_ISOTP_REQUIRE_RX_PADDING) && \
260+
!defined(CONFIG_ISOTP_ENABLE_TX_PADDING)
249261
zassert_equal(frame.dlc, desired->length,
250262
"DLC of frame nr %d differ. Desired: %d, Got: %d",
251263
i, desired->length, frame.dlc);
264+
#endif
265+
266+
#if !defined(CONFIG_ISOTP_ENABLE_TX_PADDING)
252267
ret = check_data(frame.data, desired->data, desired->length);
253268
zassert_equal(ret, 0, "Data differ");
269+
#endif
270+
254271
desired++;
255272
}
256273
ret = k_msgq_get(msgq, &frame, K_MSEC(200));
@@ -289,7 +306,9 @@ static void prepare_cf_frames(struct frame_desired *frames, size_t frames_cnt,
289306
memcpy(&des_frames[i].data[1], data_ptr, DATA_SIZE_CF);
290307

291308
if (remaining_length < DATA_SIZE_CF) {
309+
#ifndef CONFIG_ISOTP_ENABLE_TX_PADDING
292310
frames[i].length = remaining_length + 1;
311+
#endif
293312
remaining_length = 0;
294313
}
295314

@@ -338,11 +357,13 @@ static void test_receive_sf(void)
338357
single_frame.data[0] = SF_PCI_BYTE_LEN_8;
339358
send_frame_series(&single_frame, 1, rx_addr.std_id);
340359

360+
#ifdef CONFIG_ISOTP_REQUIRE_RX_PADDING
341361
single_frame.data[0] = SF_PCI_BYTE_1;
342362
single_frame.length = 7;
343363
send_frame_series(&single_frame, 1, rx_addr.std_id);
344364

345365
get_sf_ignore(&recv_ctx);
366+
#endif
346367

347368
isotp_unbind(&recv_ctx);
348369
}
@@ -392,11 +413,13 @@ static void test_receive_sf_ext(void)
392413
single_frame.data[1] = SF_PCI_BYTE_1;
393414
send_frame_series(&single_frame, 1, rx_addr.std_id);
394415

416+
#ifdef CONFIG_ISOTP_REQUIRE_RX_PADDING
395417
single_frame.data[1] = SF_PCI_BYTE_2_EXT;
396418
single_frame.length = 7;
397419
send_frame_series(&single_frame, 1, rx_addr.std_id);
398420

399421
get_sf_ignore(&recv_ctx);
422+
#endif
400423

401424
isotp_unbind(&recv_ctx);
402425
}
@@ -418,7 +441,7 @@ static void test_send_data(void)
418441
fc_frame.data[0] = FC_PCI_BYTE_1(FC_PCI_CTS);
419442
fc_frame.data[1] = FC_PCI_BYTE_2(0);
420443
fc_frame.data[2] = FC_PCI_BYTE_3(0);
421-
fc_frame.length = 3;
444+
fc_frame.length = DATA_SIZE_FC;
422445

423446
prepare_cf_frames(des_frames, ARRAY_SIZE(des_frames), data_ptr,
424447
remaining_length);
@@ -457,7 +480,7 @@ static void test_send_data_blocks(void)
457480
fc_frame.data[0] = FC_PCI_BYTE_1(FC_PCI_CTS);
458481
fc_frame.data[1] = FC_PCI_BYTE_2(fc_opts.bs);
459482
fc_frame.data[2] = FC_PCI_BYTE_3(0);
460-
fc_frame.length = 3;
483+
fc_frame.length = DATA_SIZE_FC;
461484

462485
prepare_cf_frames(des_frames, ARRAY_SIZE(des_frames), data_ptr,
463486
remaining_length);
@@ -520,7 +543,7 @@ static void test_receive_data(void)
520543
fc_frame.data[0] = FC_PCI_BYTE_1(FC_PCI_CTS);
521544
fc_frame.data[1] = FC_PCI_BYTE_2(fc_opts_single.bs);
522545
fc_frame.data[2] = FC_PCI_BYTE_3(fc_opts_single.stmin);
523-
fc_frame.length = 3;
546+
fc_frame.length = DATA_SIZE_FC;
524547

525548
prepare_cf_frames(des_frames, ARRAY_SIZE(des_frames), data_ptr,
526549
remaining_length);
@@ -564,7 +587,7 @@ static void test_receive_data_blocks(void)
564587
fc_frame.data[0] = FC_PCI_BYTE_1(FC_PCI_CTS);
565588
fc_frame.data[1] = FC_PCI_BYTE_2(fc_opts.bs);
566589
fc_frame.data[2] = FC_PCI_BYTE_3(fc_opts.stmin);
567-
fc_frame.length = 3;
590+
fc_frame.length = DATA_SIZE_FC;
568591

569592
prepare_cf_frames(des_frames, ARRAY_SIZE(des_frames), data_ptr,
570593
remaining_length);
@@ -615,7 +638,7 @@ static void test_send_timeouts(void)
615638
fc_cts_frame.data[0] = FC_PCI_BYTE_1(FC_PCI_CTS);
616639
fc_cts_frame.data[1] = FC_PCI_BYTE_2(fc_opts.bs);
617640
fc_cts_frame.data[2] = FC_PCI_BYTE_3(0);
618-
fc_cts_frame.length = 3;
641+
fc_cts_frame.length = DATA_SIZE_FC;
619642

620643
/* Test timeout for first FC*/
621644
start_time = k_uptime_get_32();
@@ -716,7 +739,7 @@ static void test_stmin(void)
716739
fc_frame.data[0] = FC_PCI_BYTE_1(FC_PCI_CTS);
717740
fc_frame.data[1] = FC_PCI_BYTE_2(2);
718741
fc_frame.data[2] = FC_PCI_BYTE_3(STMIN_VAL_1);
719-
fc_frame.length = 3;
742+
fc_frame.length = DATA_SIZE_FC;
720743

721744
filter_id = attach_msgq(rx_addr.std_id);
722745
zassert_true((filter_id >= 0), "Negative filter number [%d]",
@@ -771,7 +794,7 @@ void test_receiver_fc_errors(void)
771794
fc_frame.data[0] = FC_PCI_BYTE_1(FC_PCI_CTS);
772795
fc_frame.data[1] = FC_PCI_BYTE_2(fc_opts.bs);
773796
fc_frame.data[2] = FC_PCI_BYTE_3(fc_opts.stmin);
774-
fc_frame.length = 3;
797+
fc_frame.length = DATA_SIZE_FC;
775798

776799
filter_id = attach_msgq(tx_addr.std_id);
777800
zassert_true((filter_id >= 0), "Negative filter number [%d]",
@@ -819,7 +842,7 @@ void test_sender_fc_errors(void)
819842
fc_frame.data[0] = FC_PCI_BYTE_1(3);
820843
fc_frame.data[1] = FC_PCI_BYTE_2(fc_opts.bs);
821844
fc_frame.data[2] = FC_PCI_BYTE_3(fc_opts.stmin);
822-
fc_frame.length = 3;
845+
fc_frame.length = DATA_SIZE_FC;
823846

824847
k_sem_reset(&send_compl_sem);
825848
ret = isotp_send(&send_ctx, can_dev, random_data, DATA_SEND_LENGTH,
@@ -841,7 +864,7 @@ void test_sender_fc_errors(void)
841864
ret = isotp_send(&send_ctx, can_dev, random_data, 5*1024,
842865
&tx_addr, &rx_addr, NULL, NULL);
843866
zassert_equal(ret, ISOTP_N_BUFFER_OVERFLW,
844-
"Expected overflow bot got %d", ret);
867+
"Expected overflow but got %d", ret);
845868
isotp_unbind(&recv_ctx);
846869
filter_id = attach_msgq(tx_addr.std_id);
847870

0 commit comments

Comments
 (0)