iso14229 0.11.0
ISO14229-1 (UDS) C Library
Loading...
Searching...
No Matches
iso14229.c
Go to the documentation of this file.
1/**
2 * @file iso14229.c
3 * SPDX-License-Identifier: MIT
4 * @brief ISO 14229 (UDS) library
5 * @copyright Copyright (c) Nick Kirkby
6 * @see documentation at https://github.com/driftregion/iso14229
7 */
8
9#include "iso14229.h"
10
11#ifdef UDS_LINES
12#line 1 "src/include_private.h"
13#endif // #ifdef UDS_LINES
14
15
16#include <assert.h>
17#include <inttypes.h>
18
19#if UDS_SYS == UDS_SYS_UNIX
20#include <sys/time.h>
21/* cppcheck-suppress [misra-c2012-21.10]. This is a platform-specific port. */
22#include <time.h>
23#endif // if UDS_SYS == UDS_SYS_UNIX
24
25#if UDS_SYS == UDS_SYS_WINDOWS
26#include <stdlib.h>
27#include <time.h>
28#endif // if UDS_SYS == UDS_SYS_WINDOWS
29
30#if UDS_SYS == UDS_SYS_ARDUINO
31#include <Arduino.h>
32#endif // if UDS_SYS == UDS_SYS_ARDUINO
33
34#if UDS_SYS == UDS_SYS_ESP32
35#include <esp_timer.h>
36#endif // if UDS_SYS == UDS_SYS_ESP32
37
38#if UDS_SYS == UDS_SYS_ZEPHYR
39#include <zephyr/kernel.h>
40#endif // if UDS_SYS == UDS_SYS_ZEPHYR
41
42#if UDS_LOG_LEVEL > UDS_LOG_NONE
43#include <stdio.h>
44#include <stdarg.h>
45#endif // UDS_LOG_LEVEL > UDS_LOG_NONE
46
47#ifdef UDS_TP_ISOTP_C_SOCKETCAN
48#include <errno.h>
49#include <linux/can.h>
50#include <linux/can/raw.h>
51#include <net/if.h>
52#include <stdarg.h>
53#include <stdbool.h>
54#include <stdint.h>
55#include <stdlib.h>
56#include <sys/ioctl.h>
57#include <unistd.h>
58#endif // defined(UDS_TP_ISOTP_C_SOCKETCAN)
59
60#ifdef UDS_TP_ISOTP_SOCK
61#include <errno.h>
62#include <linux/can.h>
63#include <linux/can/isotp.h>
64#include <net/if.h>
65#include <poll.h>
66#include <string.h>
67#include <sys/ioctl.h>
68#include <sys/socket.h>
69#include <unistd.h>
70#endif // defined(UDS_TP_ISOTP_SOCK)
71
72
73#ifdef UDS_LINES
74#line 1 "src/uds_private.h"
75#endif // #ifdef UDS_LINES
76
77/// \cond DOXYGEN_SHOULD_SKIP_THIS
78#define UDS_NEG_RESP_LEN 3U
79#define UDS_0X10_REQ_LEN 2U
80#define UDS_0X10_RESP_LEN 6U
81#define UDS_0X11_REQ_MIN_LEN 2U
82#define UDS_0X11_RESP_BASE_LEN 2U
83#define UDS_0X14_REQ_MIN_LEN 4U
84#define UDS_0X14_RESP_BASE_LEN 1U
85#define UDS_0X19_REQ_MIN_LEN 2U
86#define UDS_0X19_RESP_BASE_LEN 2U
87#define UDS_0X23_REQ_MIN_LEN 4U
88#define UDS_0X23_RESP_BASE_LEN 1U
89#define UDS_0X22_RESP_BASE_LEN 1U
90#define UDS_0X27_REQ_BASE_LEN 2U
91#define UDS_0X27_RESP_BASE_LEN 2U
92#define UDS_0X28_REQ_BASE_LEN 3U
93#define UDS_0X28_RESP_LEN 2U
94#define UDS_0X2C_REQ_MIN_LEN 2U
95#define UDS_0X2C_RESP_BASE_LEN 2U
96#define UDS_0X2E_REQ_BASE_LEN 3U
97#define UDS_0X2E_REQ_MIN_LEN 4U
98#define UDS_0X2E_RESP_LEN 3U
99#define UDS_0X2F_REQ_MIN_LEN 4U
100#define UDS_0X2F_RESP_BASE_LEN 4U
101#define UDS_0X31_REQ_MIN_LEN 4U
102#define UDS_0X31_REQ_BASE_LEN 4U
103#define UDS_0X31_RESP_MIN_LEN 4U
104#define UDS_0X34_REQ_BASE_LEN 3U
105#define UDS_0X34_RESP_BASE_LEN 2U
106#define UDS_0X35_REQ_BASE_LEN 3U
107#define UDS_0X35_RESP_BASE_LEN 2U
108#define UDS_0X36_REQ_BASE_LEN 2U
109#define UDS_0X36_RESP_BASE_LEN 2U
110#define UDS_0X37_REQ_BASE_LEN 1U
111#define UDS_0X37_RESP_BASE_LEN 1U
112#define UDS_0X38_REQ_BASE_LEN 5U
113#define UDS_0X38_RESP_BASE_LEN 2U
114#define UDS_0X3D_REQ_MIN_LEN 5U
115#define UDS_0X3D_RESP_BASE_LEN 2U
116#define UDS_0X3E_REQ_MIN_LEN 2U
117#define UDS_0X3E_REQ_MAX_LEN 2U
118#define UDS_0X3E_RESP_LEN 2U
119#define UDS_0X85_REQ_BASE_LEN 2U
120#define UDS_0X85_RESP_LEN 2U
121#define UDS_0X87_REQ_BASE_LEN 2U
122#define UDS_0X87_RESP_LEN 2U
123
124#define UDS_SID_DIAGNOSTIC_SESSION_CONTROL 0x10U
125#define UDS_SID_ECU_RESET 0x11U
126#define UDS_SID_CLEAR_DIAGNOSTIC_INFORMATION 0x14U
127#define UDS_SID_READ_DTC_INFORMATION 0x19U
128#define UDS_SID_READ_DATA_BY_IDENTIFIER 0x22U
129#define UDS_SID_READ_MEMORY_BY_ADDRESS 0x23U
130#define UDS_SID_READ_SCALING_DATA_BY_IDENTIFIER 0x24U
131#define UDS_SID_SECURITY_ACCESS 0x27U
132#define UDS_SID_COMMUNICATION_CONTROL 0x28U
133#define UDS_SID_READ_PERIODIC_DATA_BY_IDENTIFIER 0x2AU
134#define UDS_SID_DYNAMICALLY_DEFINE_DATA_IDENTIFIER 0x2CU
135#define UDS_SID_WRITE_DATA_BY_IDENTIFIER 0x2EU
136#define UDS_SID_IO_CONTROL_BY_IDENTIFIER 0x2FU
137#define UDS_SID_ROUTINE_CONTROL 0x31U
138#define UDS_SID_REQUEST_DOWNLOAD 0x34U
139#define UDS_SID_REQUEST_UPLOAD 0x35U
140#define UDS_SID_TRANSFER_DATA 0x36U
141#define UDS_SID_REQUEST_TRANSFER_EXIT 0x37U
142#define UDS_SID_REQUEST_FILE_TRANSFER 0x38U
143#define UDS_SID_WRITE_MEMORY_BY_ADDRESS 0x3DU
144#define UDS_SID_TESTER_PRESENT 0x3EU
145#define UDS_SID_ACCESS_TIMING_PARAMETER 0x83U
146#define UDS_SID_SECURED_DATA_TRANSMISSION 0x84U
147#define UDS_SID_CONTROL_DTC_SETTING 0x85U
148#define UDS_SID_RESPONSE_ON_EVENT 0x86U
149#define UDS_SID_LINK_CONTROL 0x87U
150
151/// \endcond
152
153#ifdef UDS_LINES
154#line 1 "src/util_static.c"
155#endif // #ifdef UDS_LINES
156
157
158
159
160/// Serializes n bytes of val to *dst in big-endian format.
161static void PackBE(uint8_t *dst, uint64_t val, size_t n) {
162 for (size_t i = 0; i < n; i++) {
163 dst[i] = (uint8_t)(val >> (8U * (n - 1U - i)));
164 }
165}
166
167/**
168 * @brief Unpack up to sizeof(size_t) big-endian bytes from src.
169 * @param src buffer
170 * @param n ranges from 0 to sizeof(size_t) inclusive
171 * @return unpacked quantity
172 */
173static size_t UnpackBEsize(const uint8_t *src, size_t n) {
174 UDS_ASSERT(src != NULL);
175 UDS_ASSERT(n <= sizeof(size_t));
176
177 size_t val = 0;
178 for (size_t i = 0; i < n; i++) {
179 val = (val << 8U) | src[i];
180 }
181 return val;
182}
183
184/**
185 * @brief Unpack up to sizeof(uintptr_t) big-endian bytes from src.
186 * @param src buffer
187 * @param n ranges from 0 to sizeof(uintptr_t) inclusive
188 * @return unpacked quantity
189 */
190static uintptr_t UnpackBEuintptr(const uint8_t *src, size_t n) {
191 UDS_ASSERT(src != NULL);
192 UDS_ASSERT(n <= sizeof(uintptr_t));
193
194 uintptr_t val = 0;
195 for (size_t i = 0; i < n; i++) {
196 val = (val << 8U) | src[i];
197 }
198 return val;
199}
200
201/**
202 * @brief Unpack up to 4 big-endian bytes from src into dst as uint32_t.
203 * @param src buffer
204 * @param n ranges from 0 to 4 inclusive
205 * @return unpacked quantity
206 */
207static uint32_t UnpackBEu32(const uint8_t *src, size_t n) {
208 UDS_ASSERT(src != NULL);
209 UDS_ASSERT(n <= sizeof(uint32_t));
210
211 uint32_t val = 0;
212 for (size_t i = 0; i < n; i++) {
213 val = (val << 8U) | src[i];
214 }
215
216 return val;
217}
218
219/**
220 * @brief Unpack 2 big-endian bytes from src into dst as uint16_t.
221 * @param src buffer
222 * @param dst pointer to destination
223 * @return UDS_OK if successful
224 */
225static uint16_t UnpackBEu16(const uint8_t *src) {
226 UDS_ASSERT(src);
227 return (uint16_t)((uint16_t)(src[0] << 8U) | (uint16_t)src[1]);
228}
229
230static uint8_t AsResponseSID(uint8_t request_sid) {
231 UDS_ASSERT(request_sid <= (UINT8_MAX - 0x40U));
232 return request_sid + 0x40U;
233}
234
235static uint8_t AsRequestSID(uint8_t response_sid) {
236 UDS_ASSERT(response_sid >= 0x40U);
237 return response_sid - 0x40U;
238}
239
240/**
241 * @brief Check whether one timestamp is after another, correctly handling wrap-around
242 * @param a: timestamp to check
243 * @param b: reference timestamp
244 * @return true if `a` is after `b`
245 * @note Do not use for durations > 10 days.
246 *
247 * The upper limit is 2**32 / 2 / 1000 / 60 / 60 / 24 = 24.8 days.
248 * TODO: There is likely some buggy behavior after this time has elapsed. Mitigate this.
249 *
250 */
251static bool UDSTimeAfter(uint32_t a, uint32_t b) {
252 uint32_t diff = a - b;
253 return (diff - 1U) < 0x7FFFFFFFU;
254}
255
256/// returns true if a security level is reserved per ISO14229-1:2020 Table 42
257// See ISO14229-1:2020 Table 42 — Request message SubFunction parameter definition
258static bool UDSSecurityAccessLevelIsReserved(uint8_t subFunction) {
259 if (0U == subFunction) {
260 return true;
261 }
262 if (subFunction <= 0x42U) {
263 return false;
264 }
265 if (subFunction <= 0x5EU) {
266 return true;
267 }
268 if (subFunction <= 0x7EU) {
269 return false;
270 }
271 return true;
272}
273
274/// returns true if err is defined in ISO14229-1:2020 as an NRC
275static bool UDSErrIsNRC(UDSErr_t err) {
276 switch (err) {
277 case UDS_PositiveResponse:
278 case UDS_NRC_GeneralReject:
279 case UDS_NRC_ServiceNotSupported:
280 case UDS_NRC_SubFunctionNotSupported:
281 case UDS_NRC_IncorrectMessageLengthOrInvalidFormat:
282 case UDS_NRC_ResponseTooLong:
283 case UDS_NRC_BusyRepeatRequest:
284 case UDS_NRC_ConditionsNotCorrect:
285 case UDS_NRC_RequestSequenceError:
286 case UDS_NRC_NoResponseFromSubnetComponent:
287 case UDS_NRC_FailurePreventsExecutionOfRequestedAction:
288 case UDS_NRC_RequestOutOfRange:
289 case UDS_NRC_SecurityAccessDenied:
290 case UDS_NRC_AuthenticationRequired:
291 case UDS_NRC_InvalidKey:
292 case UDS_NRC_ExceedNumberOfAttempts:
293 case UDS_NRC_RequiredTimeDelayNotExpired:
294 case UDS_NRC_SecureDataTransmissionRequired:
295 case UDS_NRC_SecureDataTransmissionNotAllowed:
296 case UDS_NRC_SecureDataVerificationFailed:
297 case UDS_NRC_CertficateVerificationFailedInvalidTimePeriod:
298 case UDS_NRC_CertficateVerificationFailedInvalidSignature:
299 case UDS_NRC_CertficateVerificationFailedInvalidChainOfTrust:
300 case UDS_NRC_CertficateVerificationFailedInvalidType:
301 case UDS_NRC_CertficateVerificationFailedInvalidFormat:
302 case UDS_NRC_CertficateVerificationFailedInvalidContent:
303 case UDS_NRC_CertficateVerificationFailedInvalidScope:
304 case UDS_NRC_CertficateVerificationFailedInvalidCertificate:
305 case UDS_NRC_OwnershipVerificationFailed:
306 case UDS_NRC_ChallengeCalculationFailed:
307 case UDS_NRC_SettingAccessRightsFailed:
308 case UDS_NRC_SessionKeyCreationOrDerivationFailed:
309 case UDS_NRC_ConfigurationDataUsageFailed:
310 case UDS_NRC_DeAuthenticationFailed:
311 case UDS_NRC_UploadDownloadNotAccepted:
312 case UDS_NRC_TransferDataSuspended:
313 case UDS_NRC_GeneralProgrammingFailure:
314 case UDS_NRC_WrongBlockSequenceCounter:
315 case UDS_NRC_RequestCorrectlyReceived_ResponsePending:
316 case UDS_NRC_SubFunctionNotSupportedInActiveSession:
317 case UDS_NRC_ServiceNotSupportedInActiveSession:
318 case UDS_NRC_RpmTooHigh:
319 case UDS_NRC_RpmTooLow:
320 case UDS_NRC_EngineIsRunning:
321 case UDS_NRC_EngineIsNotRunning:
322 case UDS_NRC_EngineRunTimeTooLow:
323 case UDS_NRC_TemperatureTooHigh:
324 case UDS_NRC_TemperatureTooLow:
325 case UDS_NRC_VehicleSpeedTooHigh:
326 case UDS_NRC_VehicleSpeedTooLow:
327 case UDS_NRC_ThrottlePedalTooHigh:
328 case UDS_NRC_ThrottlePedalTooLow:
329 case UDS_NRC_TransmissionRangeNotInNeutral:
330 case UDS_NRC_TransmissionRangeNotInGear:
331 case UDS_NRC_BrakeSwitchNotClosed:
332 case UDS_NRC_ShifterLeverNotInPark:
333 case UDS_NRC_TorqueConverterClutchLocked:
334 case UDS_NRC_VoltageTooHigh:
335 case UDS_NRC_VoltageTooLow:
336 case UDS_NRC_ResourceTemporarilyNotAvailable:
337 return true;
338 default:
339 return false;
340 }
341}
342
343
344#ifdef UDS_LINES
345#line 1 "src/client.c"
346#endif // #ifdef UDS_LINES
347
348
349
350
351
352
353
354/**
355 * @defgroup client_request_states valid values of UDSClient_t::state
356 * @brief internal state machine states for a single client request
357 * @see UDSClient_t::state
358 * @{
359 */
360#define STATE_IDLE 0U /**< no request in progress */
361#define STATE_SENDING 1U /**< request is being transmitted */
362#define STATE_AWAIT_SEND_COMPLETE 2U /**< waiting for the transport to finish sending */
363#define STATE_AWAIT_RESPONSE 3U /**< request sent, awaiting server response */
364/** @} */
365
367 if (NULL == client) {
368 return UDS_ERR_INVALID_ARG;
369 }
370 (void)memset(client, 0, sizeof(*client));
371 client->state = STATE_IDLE;
372 client->cfg_data_format_identifier = 0x00;
373 client->cfg_file_size_parameter_length = 0x04;
374
377
378 if (client->p2_star_ms < client->p2_ms) {
379 UDS_LOGE(__FILE__, "p2_star_ms must be >= p2_ms");
380 client->p2_star_ms = client->p2_ms;
381 }
382
383 return UDS_OK;
384}
385
386static const char *ClientStateName(uint8_t state) {
387 switch (state) {
388 case STATE_IDLE:
389 return "Idle";
390 case STATE_SENDING:
391 return "Sending";
393 return "AwaitSendComplete";
395 return "AwaitResponse";
396 default:
397 return "Unknown";
398 }
399}
400
401static void changeState(UDSClient_t *client, uint8_t state) {
402 if (state != client->state) {
403 UDS_LOGV(__FILE__, "client state: %s (%d) -> %s (%d)", ClientStateName(client->state),
404 client->state, ClientStateName(state), state);
405
406 client->state = state;
407
408 if (state == STATE_IDLE) {
409 client->fn(client, UDS_EVT_Idle, NULL);
410 }
411 }
412}
413
414/**
415 * @brief Check that the response is a valid UDS response
416 * @param client
417 * @return UDSErr_t
418 */
419static UDSErr_t ValidateServerResponse(const UDSClient_t *client) {
420
421 if (client->recv_size < 1U) {
422 return UDS_ERR_RESP_TOO_SHORT;
423 }
424
425 // It's a negative response
426 if (0x7FU == client->recv_buf[0]) {
427 if (client->send_buf[0] != client->recv_buf[1]) {
428 return UDS_ERR_SID_MISMATCH;
429 }
430 if (client->recv_size < 2U) {
431 return UDS_ERR_RESP_TOO_SHORT;
432 }
433 const UDSErr_t nrc = client->recv_buf[2];
434 if (nrc == UDS_NRC_RequestCorrectlyReceived_ResponsePending) {
435 return UDS_OK;
436 }
437 if (!UDSErrIsNRC(nrc)) {
438 UDS_LOGW(__FILE__, "nrc 0x%X not recognized", nrc);
439 }
440 return nrc;
441 }
442
443 // It's a positive response
444 UDS_ASSERT(0x7FU != client->recv_buf[0]);
445 if (AsResponseSID(client->send_buf[0]) != client->recv_buf[0]) {
446 return UDS_ERR_SID_MISMATCH;
447 }
448 if (client->send_buf[0] == UDS_SID_ECU_RESET) {
449 if (client->recv_size < 2U) {
450 return UDS_ERR_RESP_TOO_SHORT;
451 }
452 if (client->send_buf[1] != client->recv_buf[1]) {
453 return UDS_ERR_SUBFUNCTION_MISMATCH;
454 }
455 }
456
457 return UDS_OK;
458}
459
460/**
461 * @brief Handle validated server response
462 * @param client
463 */
464static UDSErr_t HandleServerResponse(UDSClient_t *client) {
465 if (0x7FU == client->recv_buf[0]) {
466 if ((uint8_t)UDS_NRC_RequestCorrectlyReceived_ResponsePending == client->recv_buf[2]) {
467 client->p2_timer = UDSMillis() + client->p2_star_ms;
468 UDS_LOGI(__FILE__, "got RCRRP, set p2 timer to %" PRIu32 "", client->p2_timer);
469 (void)memset(client->recv_buf, 0, sizeof(client->recv_buf));
470 client->recv_size = 0;
471 changeState(client, STATE_AWAIT_RESPONSE);
472 return UDS_NRC_RequestCorrectlyReceived_ResponsePending;
473 }
474 // else: fall-through
475 } else {
476 uint8_t respSid = client->recv_buf[0];
477 switch (AsRequestSID(respSid)) { // NOLINT(readability-trivial-switch) response handler
478 case UDS_SID_DIAGNOSTIC_SESSION_CONTROL: {
479 if (client->recv_size < UDS_0X10_RESP_LEN) {
480 UDS_LOGI(__FILE__, "Error: SID %x response too short",
481 UDS_SID_DIAGNOSTIC_SESSION_CONTROL);
482 changeState(client, STATE_IDLE);
483 return UDS_ERR_RESP_TOO_SHORT;
484 }
485
486 if (client->cfg_ignore_srv_sess_timing) {
487 changeState(client, STATE_IDLE);
488 break;
489 }
490
491 uint16_t p2 = UnpackBEu16(&client->recv_buf[2]);
492 uint32_t p2_star = (uint32_t)UnpackBEu16(&client->recv_buf[4]) * 10U;
493 UDS_LOGI(__FILE__, "received new timings: p2: %" PRIu16 ", p2*: %" PRIu32, p2, p2_star);
494 client->p2_ms = p2;
495 client->p2_star_ms = p2_star;
496 break;
497 }
498 default:
499 break;
500 }
501 }
502 return UDS_OK;
503}
504
505static void WarnIfRecvWhileSending(UDSClient_t *client) {
506 UDSSDU_t recvinfo = {0};
507 size_t recvlen = 0;
508 UDSErr_t err =
509 UDSTpRecv(client->tp, client->recv_buf, sizeof(client->recv_buf), &recvlen, &recvinfo);
510 if (UDS_OK != err) {
511 UDS_LOGE(__FILE__, "transport returned error %s", UDSErrToStr(err));
512 } else if (recvlen == 0U) {
513 ; // expected
514 } else {
515 UDS_LOGW(__FILE__, "received %zd unexpected bytes:", recvlen);
516 UDS_LOG_SDU(__FILE__, client->recv_buf, recvlen, &recvinfo);
517 }
518}
519
520static UDSErr_t Handle_SENDING(UDSClient_t *client) {
521
522 // While sending, we expect that nothing should be received,
523 // but sometimes data is received due to e.g. misconfiguration.
524 WarnIfRecvWhileSending(client);
525
526 (void)memset(client->recv_buf, 0, sizeof(client->recv_buf));
527 client->recv_size = 0;
528
529 UDS_A_TA_Type_t ta_type =
530 client->cfg_send_functional ? UDS_A_TA_TYPE_FUNCTIONAL : UDS_A_TA_TYPE_PHYSICAL;
531 UDSSDU_t info = {
532 .A_Mtype = UDS_A_MTYPE_DIAG,
533 .A_TA_Type = ta_type,
534 };
535 UDSErr_t err = UDSTpSend(client->tp, client->send_buf, client->send_size, &info);
536 if (UDS_OK != err) {
537 UDS_LOGE(__FILE__, "tport err: %s", UDSErrToStr(err));
538 } else {
539 changeState(client, STATE_AWAIT_SEND_COMPLETE);
540 }
541 return err;
542}
543
544static UDSErr_t Handle_AWAIT_SEND_COMPLETE(UDSClient_t *client) {
545 if (client->cfg_send_functional) {
546 // "The Functional addressing is applied only to single frame transmission"
547 // Specification of Diagnostic Communication (Diagnostic on CAN - Network Layer)
548 changeState(client, STATE_IDLE);
549 }
550 if (client->tp->status.is_sending) {
551 ; // await send complete
552 } else {
553 client->fn(client, UDS_EVT_SendComplete, NULL);
554 if (client->cfg_suppress_pos_resp) {
555 changeState(client, STATE_IDLE);
556 } else {
557 changeState(client, STATE_AWAIT_RESPONSE);
558 client->p2_timer = UDSMillis() + client->p2_ms;
559 }
560 }
561 return UDS_OK;
562}
563
564static UDSErr_t Handle_AWAIT_RESPONSE(UDSClient_t *client) {
565 UDSSDU_t info = {0};
566 size_t recvlen = 0;
567 UDSErr_t err =
568 UDSTpRecv(client->tp, client->recv_buf, sizeof(client->recv_buf), &recvlen, &info);
569 if (UDS_OK != err) {
570 changeState(client, STATE_IDLE);
571 } else if (0U == recvlen) {
572 if (UDSTimeAfter(UDSMillis(), client->p2_timer)) {
573 UDS_LOGI(__FILE__, "p2 timeout");
574 err = UDS_ERR_TIMEOUT;
575 changeState(client, STATE_IDLE);
576 }
577 } else {
578 UDS_LOGD(__FILE__, "received %zd bytes. Processing...", recvlen);
579 UDS_ASSERT(recvlen <= UINT16_MAX);
580 client->recv_size = recvlen;
581
582 err = ValidateServerResponse(client);
583 if (UDS_OK == err) {
584 err = HandleServerResponse(client);
585 }
586
587 if (UDS_OK == err) {
588 client->fn(client, UDS_EVT_ResponseReceived, NULL);
589 changeState(client, STATE_IDLE);
590 }
591 }
592 return err;
593}
594
595/**
596 * @brief execute the client request state machine
597 * @param client
598 */
599static UDSErr_t PollLowLevel(UDSClient_t *client) {
600 if ((NULL == client) || (NULL == client->tp) || (NULL == client->tp->poll)) {
601 return UDS_ERR_MISUSE;
602 }
603 UDS_ASSERT(client);
604 UDS_ASSERT(client->tp);
605 UDS_ASSERT(client->tp->poll);
606
607 UDSErr_t err = UDSTpPoll(client->tp);
608
609 if (UDS_OK != err) {
610 return err;
611 }
612
613 switch (client->state) {
614 case STATE_IDLE:
615 return UDS_OK;
616 case STATE_SENDING:
617 return Handle_SENDING(client);
619 return Handle_AWAIT_SEND_COMPLETE(client);
621 return Handle_AWAIT_RESPONSE(client);
622 default:
623 UDS_ASSERT(false);
624 return UDS_FAIL;
625 }
626}
627
628static UDSErr_t SendRequest(UDSClient_t *client) {
629 if (client->cfg_suppress_pos_resp) {
630 // UDS-1:2013 8.2.2 Table 11
631 client->send_buf[1] |= 0x80U;
632 }
633
634 changeState(client, STATE_SENDING);
635 UDSErr_t err = PollLowLevel(client); // poll once to begin sending immediately
636 return err;
637}
638
639static UDSErr_t PreRequestCheck(UDSClient_t *client) {
640 if (NULL == client) {
641 return UDS_ERR_INVALID_ARG;
642 }
643 if (STATE_IDLE != client->state) {
644 return UDS_ERR_BUSY;
645 }
646 if (client->tp == NULL) {
647 return UDS_ERR_TPORT;
648 }
649 client->recv_size = 0;
650 client->send_size = 0;
651 return UDS_OK;
652}
653
654UDSErr_t UDSSendBytes(UDSClient_t *client, const uint8_t *data, uint16_t size) {
655 UDSErr_t err = PreRequestCheck(client);
656 if (UDS_OK != err) {
657 return err;
658 }
659 if (size > sizeof(client->send_buf)) {
660 return UDS_ERR_BUFSIZ;
661 }
662 (void)memmove(client->send_buf, data, size);
663 client->send_size = size;
664 return SendRequest(client);
665}
666
667UDSErr_t UDSSendECUReset(UDSClient_t *client, uint8_t type) {
668 UDSErr_t err = PreRequestCheck(client);
669 if (UDS_OK != err) {
670 return err;
671 }
672 client->send_buf[0] = UDS_SID_ECU_RESET;
673 client->send_buf[1] = type;
674 client->send_size = 2;
675 return SendRequest(client);
676}
677
679 UDSErr_t err = PreRequestCheck(client);
680 if (UDS_OK != err) {
681 return err;
682 }
683 client->send_buf[0] = UDS_SID_DIAGNOSTIC_SESSION_CONTROL;
684 client->send_buf[1] = mode;
685 client->send_size = 2;
686 return SendRequest(client);
687}
688
689UDSErr_t UDSSendCommCtrl(UDSClient_t *client, uint8_t ctrl, uint8_t comm) {
690 UDSErr_t err = PreRequestCheck(client);
691 if (UDS_OK != err) {
692 return err;
693 }
694 client->send_buf[0] = UDS_SID_COMMUNICATION_CONTROL;
695 client->send_buf[1] = ctrl;
696 client->send_buf[2] = comm;
697 client->send_size = 3;
698 return SendRequest(client);
699}
700
702 UDSErr_t err = PreRequestCheck(client);
703 if (UDS_OK != err) {
704 return err;
705 }
706 client->send_buf[0] = UDS_SID_TESTER_PRESENT;
707 client->send_buf[1] = 0;
708 client->send_size = 2;
709 return SendRequest(client);
710}
711
712UDSErr_t UDSSendRDBI(UDSClient_t *client, const uint16_t *didList,
713 const uint16_t numDataIdentifiers) {
714 UDSErr_t err = PreRequestCheck(client);
715 if (UDS_OK != err) {
716 return err;
717 }
718 if ((NULL == didList) || (0U == numDataIdentifiers)) {
719 return UDS_ERR_INVALID_ARG;
720 }
721
722 const size_t send_size = 1U + ((size_t)numDataIdentifiers * 2U);
723 if (send_size > sizeof(client->send_buf)) {
724 return UDS_ERR_BUFSIZ;
725 }
726
727 client->send_buf[0] = UDS_SID_READ_DATA_BY_IDENTIFIER;
728 for (uint16_t i = 0U; i < numDataIdentifiers; i++) {
729 uint16_t offset = (uint16_t)(1U + (i * 2U));
730 PackBE(&client->send_buf[offset], didList[i], 2);
731 }
732 client->send_size = send_size;
733 return SendRequest(client);
734}
735
736UDSErr_t UDSSendWDBI(UDSClient_t *client, uint16_t dataIdentifier, const uint8_t *data,
737 uint16_t size) {
738 UDSErr_t err = PreRequestCheck(client);
739 if (UDS_OK != err) {
740 return err;
741 }
742 if ((data == NULL) || (size == 0U)) {
743 return UDS_ERR_INVALID_ARG;
744 }
745 const size_t send_size = UDS_0X2E_REQ_BASE_LEN + (size_t)size;
746 if (send_size > sizeof(client->send_buf)) {
747 return UDS_ERR_BUFSIZ;
748 }
749
750 client->send_buf[0] = UDS_SID_WRITE_DATA_BY_IDENTIFIER;
751 PackBE(&client->send_buf[1], dataIdentifier, 2);
752 (void)memmove(&client->send_buf[UDS_0X2E_REQ_BASE_LEN], data, size);
753 client->send_size = send_size;
754 return SendRequest(client);
755}
756
757/**
758 * @brief RoutineControl
759 *
760 * @param client
761 * @param type
762 * @param routineIdentifier
763 * @param data
764 * @param size
765 * @return UDSErr_t
766 * @addtogroup routineControl_0x31
767 */
768UDSErr_t UDSSendRoutineCtrl(UDSClient_t *client, uint8_t type, uint16_t routineIdentifier,
769 const uint8_t *data, uint16_t size) {
770 UDSErr_t err = PreRequestCheck(client);
771 if (UDS_OK != err) {
772 return err;
773 }
774 client->send_buf[0] = UDS_SID_ROUTINE_CONTROL;
775 client->send_buf[1] = type;
776 client->send_buf[2] = routineIdentifier >> 8U;
777 client->send_buf[3] = routineIdentifier & 0xFFU;
778
779 if ((0U != size) && (data == NULL)) {
780 return UDS_ERR_INVALID_ARG;
781 }
782
783 const size_t send_size = UDS_0X31_REQ_BASE_LEN + (size_t)size;
784 if (send_size > sizeof(client->send_buf)) {
785 return UDS_ERR_BUFSIZ;
786 }
787
788 (void)memmove(&client->send_buf[UDS_0X31_REQ_BASE_LEN], data, size);
789 client->send_size = send_size;
790 return SendRequest(client);
791}
792
793/**
794 * @brief
795 *
796 * @param client
797 * @param dataFormatIdentifier
798 * @param addressAndLengthFormatIdentifier
799 * @param memoryAddress
800 * @param memorySize
801 * @return UDSErr_t
802 * @addtogroup requestDownload_0x34
803 */
804UDSErr_t UDSSendRequestDownload(UDSClient_t *client, uint8_t dataFormatIdentifier,
805 uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
806 size_t memorySize) {
807 UDSErr_t err = PreRequestCheck(client);
808 if (UDS_OK != err) {
809 return err;
810 }
811 uint8_t numMemorySizeBytes = (uint8_t)((addressAndLengthFormatIdentifier & 0xF0U) >> 4U);
812 uint8_t numMemoryAddressBytes = (uint8_t)(addressAndLengthFormatIdentifier & 0x0FU);
813 const size_t send_size = 3U + (size_t)numMemoryAddressBytes + (size_t)numMemorySizeBytes;
814
815 if (send_size > sizeof(client->send_buf)) {
816 return UDS_ERR_BUFSIZ;
817 }
818
819 client->send_buf[0] = UDS_SID_REQUEST_DOWNLOAD;
820 client->send_buf[1] = dataFormatIdentifier;
821 client->send_buf[2] = addressAndLengthFormatIdentifier;
822
823 PackBE(&client->send_buf[3], memoryAddress, numMemoryAddressBytes);
824 PackBE(&client->send_buf[3U + numMemoryAddressBytes], memorySize, numMemorySizeBytes);
825
826 client->send_size = send_size;
827 return SendRequest(client);
828}
829
830/**
831 * @brief
832 *
833 * @param client
834 * @param dataFormatIdentifier
835 * @param addressAndLengthFormatIdentifier
836 * @param memoryAddress
837 * @param memorySize
838 * @return UDSErr_t
839 * @addtogroup requestDownload_0x35
840 */
841UDSErr_t UDSSendRequestUpload(UDSClient_t *client, uint8_t dataFormatIdentifier,
842 uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
843 size_t memorySize) {
844 UDSErr_t err = PreRequestCheck(client);
845 if (UDS_OK != err) {
846 return err;
847 }
848 uint8_t numMemorySizeBytes = (uint8_t)((addressAndLengthFormatIdentifier & 0xF0U) >> 4U);
849 uint8_t numMemoryAddressBytes = (uint8_t)(addressAndLengthFormatIdentifier & 0x0FU);
850 const size_t send_size = 3U + (size_t)numMemoryAddressBytes + (size_t)numMemorySizeBytes;
851 if (sizeof(client->send_buf) < send_size) {
852 return UDS_ERR_BUFSIZ;
853 }
854
855 client->send_buf[0] = UDS_SID_REQUEST_UPLOAD;
856 client->send_buf[1] = dataFormatIdentifier;
857 client->send_buf[2] = addressAndLengthFormatIdentifier;
858
859 PackBE(&client->send_buf[3], memoryAddress, numMemoryAddressBytes);
860 PackBE(&client->send_buf[3U + numMemoryAddressBytes], memorySize, numMemorySizeBytes);
861
862 client->send_size = send_size;
863 return SendRequest(client);
864}
865
866/**
867 * @brief
868 *
869 * @param client
870 * @param blockSequenceCounter
871 * @param blockLength
872 * @param fd
873 * @return UDSErr_t
874 * @addtogroup transferData_0x36
875 */
876UDSErr_t UDSSendTransferData(UDSClient_t *client, uint8_t blockSequenceCounter,
877 const uint16_t blockLength, const uint8_t *data, uint16_t size) {
878 UDSErr_t err = PreRequestCheck(client);
879 if (UDS_OK != err) {
880 return err;
881 }
882
883 // blockLength must include SID and sequenceCounter
884 if (blockLength <= 2U) {
885 return UDS_ERR_INVALID_ARG;
886 }
887
888 // data must fit inside blockLength - 2
889 if (size > (blockLength - 2U)) {
890 return UDS_ERR_INVALID_ARG;
891 }
892 client->send_buf[0] = UDS_SID_TRANSFER_DATA;
893 client->send_buf[1] = blockSequenceCounter;
894 (void)memmove(&client->send_buf[UDS_0X36_REQ_BASE_LEN], data, size);
895 UDS_LOGI(__FILE__, "size: %d, blocklength: %d", size, blockLength);
896 client->send_size = UDS_0X36_REQ_BASE_LEN + (size_t)size;
897 return SendRequest(client);
898}
899
900/**
901 * @brief
902 *
903 * @param client
904 * @return UDSErr_t
905 * @addtogroup requestTransferExit_0x37
906 */
908 UDSErr_t err = PreRequestCheck(client);
909 if (UDS_OK != err) {
910 return err;
911 }
912 client->send_buf[0] = UDS_SID_REQUEST_TRANSFER_EXIT;
913 client->send_size = 1;
914 return SendRequest(client);
915}
916
917UDSErr_t UDSSendRequestFileTransfer(UDSClient_t *client, const uint8_t mode, const char *filePath,
918 const size_t filePathLen, const size_t fileSizeUncompressed,
919 const size_t fileSizeCompressed) {
920 UDSErr_t err = PreRequestCheck(client);
921 if (UDS_OK != err) {
922 return err;
923 }
924 if (filePath == NULL) {
925 return UDS_ERR_INVALID_ARG;
926 }
927 // the protocol dictates a two byte maximum.
928 // additional length checks are per-case.
929 if (filePathLen > (size_t)UINT16_MAX) {
930 return UDS_ERR_INVALID_ARG;
931 }
932 /*
933 Pre-compute the request length based on the MOOP.
934 For each field, "Y" denotes present and "_" denotes absent.
935
936 ADDFILE -- AddFile
937 | DELFILE -- DeleteFile
938 | | REPLFILE -- ReplaceFile
939 | | | RDFILE -- ReadFile
940 | | | | RDDIR -- ReadDirectory
941 | | | | | RSFILE -- ResumeFile
942 | | | | | |
943 MOOP 1 2 3 4 5 6
944 field | size (bytes)
945 Request SID Y Y Y Y Y Y | 1
946 modeOfOperation Y Y Y Y Y Y | 1
947 filePathAndNameLength Y Y Y Y Y Y | 2
948 filePathAndName Y Y Y Y Y Y | variable: u16_filePathLen
949 dataFormatIdentifier Y _ Y Y _ Y | 1
950 fileSizeParameterLength Y _ Y _ _ Y | 1
951 fileSizeUncompressed Y _ Y _ _ Y | variable: cfg_file_size_parameter_length
952 fileSizeCompressed Y _ Y _ _ Y | variable: cfg_file_size_parameter_length
953 */
954 size_t send_size = SIZE_MAX; // set by the MOOP-specific case below
955 switch (mode) {
956 case UDS_MOOP_ADDFILE: // MOOP = 1
957 case UDS_MOOP_REPLFILE: // MOOP = 3
958 case UDS_MOOP_RSFILE: // MOOP = 6
959 {
960 send_size = 4U + filePathLen + 2U + (size_t)(2U * client->cfg_file_size_parameter_length);
961 if (send_size > sizeof(client->send_buf)) {
962 return UDS_ERR_BUFSIZ;
963 }
964 client->send_buf[0] = UDS_SID_REQUEST_FILE_TRANSFER;
965 client->send_buf[1] = mode;
966 PackBE(&client->send_buf[2], filePathLen, 2); // filePathAndNameLength
967 (void)memmove(&client->send_buf[4], filePath, filePathLen); // filePathAndName
968 client->send_buf[4U + filePathLen] = client->cfg_data_format_identifier;
969 client->send_buf[5U + filePathLen] = client->cfg_file_size_parameter_length;
970 PackBE(&client->send_buf[6U + filePathLen], fileSizeUncompressed,
972 PackBE(&client->send_buf[6U + filePathLen + client->cfg_file_size_parameter_length],
973 fileSizeCompressed, client->cfg_file_size_parameter_length);
974 break;
975 }
976 case UDS_MOOP_DELFILE: // MOOP = 2
977 case UDS_MOOP_RDDIR: // MOOP = 5
978 {
979 send_size = 4U + filePathLen + 1U;
980 if (send_size > sizeof(client->send_buf)) {
981 return UDS_ERR_BUFSIZ;
982 }
983 client->send_buf[0] = UDS_SID_REQUEST_FILE_TRANSFER;
984 client->send_buf[1] = mode;
985 PackBE(&client->send_buf[2], filePathLen, 2); // filePathAndNameLength
986 (void)memmove(&client->send_buf[4], filePath, filePathLen); // filePathAndName
987 break;
988 }
989 case UDS_MOOP_RDFILE: { // MOOP = 4
990 send_size = 4U + filePathLen + 1U;
991 if (send_size > sizeof(client->send_buf)) {
992 return UDS_ERR_BUFSIZ;
993 }
994 client->send_buf[0] = UDS_SID_REQUEST_FILE_TRANSFER;
995 client->send_buf[1] = mode;
996 PackBE(&client->send_buf[2], filePathLen, 2); // filePathAndNameLength
997 (void)memmove(&client->send_buf[4], filePath, filePathLen); // filePathAndName
998 client->send_buf[4U + filePathLen] = client->cfg_data_format_identifier;
999 break;
1000 }
1001 default:
1002 UDS_ASSERT(false);
1003 break;
1004 }
1005 // Phew!
1006
1007 UDS_ASSERT(send_size != SIZE_MAX);
1008 client->send_size = send_size;
1009 return SendRequest(client);
1010}
1011
1012/**
1013 * @brief
1014 *
1015 * @param client
1016 * @param dtcSettingType
1017 * @param data
1018 * @param size
1019 * @return UDSErr_t
1020 * @addtogroup controlDTCSetting_0x85
1021 */
1022UDSErr_t UDSCtrlDTCSetting(UDSClient_t *client, uint8_t dtcSettingType,
1023 const uint8_t *dtcSettingControlOptionRecord, uint16_t len) {
1024 UDSErr_t err = PreRequestCheck(client);
1025 if (UDS_OK != err) {
1026 return err;
1027 }
1028
1029 // these are reserved values
1030 if ((0x00U == dtcSettingType) || (0x7FU == dtcSettingType) ||
1031 ((0x03U <= dtcSettingType) && (dtcSettingType <= 0x3FU))) {
1032 return UDS_ERR_INVALID_ARG;
1033 }
1034
1035 if ((len != 0U) && (NULL == dtcSettingControlOptionRecord)) {
1036 return UDS_ERR_INVALID_ARG;
1037 }
1038
1039 const size_t send_size = 2U + (size_t)len;
1040 if (send_size > sizeof(client->send_buf)) {
1041 return UDS_ERR_BUFSIZ;
1042 }
1043
1044 client->send_buf[0] = UDS_SID_CONTROL_DTC_SETTING;
1045 client->send_buf[1] = dtcSettingType;
1046 (void)memmove(&client->send_buf[2], dtcSettingControlOptionRecord, len);
1047
1048 client->send_size = send_size;
1049 return SendRequest(client);
1050}
1051
1052/**
1053 * @brief
1054 *
1055 * @param client
1056 * @param level
1057 * @param data
1058 * @param size
1059 * @return UDSErr_t
1060 * @addtogroup securityAccess_0x27
1061 */
1062UDSErr_t UDSSendSecurityAccess(UDSClient_t *client, uint8_t level, const uint8_t *data,
1063 uint16_t size) {
1064 UDSErr_t err = PreRequestCheck(client);
1065 if (UDS_OK != err) {
1066 return err;
1067 }
1068 if (UDSSecurityAccessLevelIsReserved(level)) {
1069 return UDS_ERR_INVALID_ARG;
1070 }
1071
1072 if ((NULL == data) && (0U != size)) {
1073 return UDS_ERR_INVALID_ARG;
1074 }
1075
1076 const size_t send_size = UDS_0X27_REQ_BASE_LEN + (size_t)size;
1077 if (send_size > sizeof(client->send_buf)) {
1078 return UDS_ERR_BUFSIZ;
1079 }
1080
1081 client->send_buf[0] = UDS_SID_SECURITY_ACCESS;
1082 client->send_buf[1] = level;
1083 if (NULL != data) {
1084 (void)memmove(&client->send_buf[UDS_0X27_REQ_BASE_LEN], data, size);
1085 }
1086
1087 client->send_size = send_size;
1088 return SendRequest(client);
1089}
1090
1091/**
1092 * @brief
1093 *
1094 * @param client
1095 * @param resp
1096 * @return UDSErr_t
1097 * @addtogroup securityAccess_0x27
1098 */
1100 struct SecurityAccessResponse *resp) {
1101 if ((NULL == client) || (NULL == resp)) {
1102 return UDS_ERR_INVALID_ARG;
1103 }
1104 if (AsResponseSID(UDS_SID_SECURITY_ACCESS) != client->recv_buf[0]) {
1105 return UDS_ERR_SID_MISMATCH;
1106 }
1107 if (client->recv_size < UDS_0X27_RESP_BASE_LEN) {
1108 return UDS_ERR_RESP_TOO_SHORT;
1109 }
1110 resp->securityAccessType = client->recv_buf[1];
1111 resp->securitySeedLength = client->recv_size - UDS_0X27_RESP_BASE_LEN;
1112 resp->securitySeed = (resp->securitySeedLength == 0U) ? NULL : &client->recv_buf[2];
1113 return UDS_OK;
1114}
1115
1116/**
1117 * @brief
1118 *
1119 * @param client
1120 * @param resp
1121 * @return UDSErr_t
1122 * @addtogroup routineControl_0x31
1123 */
1125 struct RoutineControlResponse *resp) {
1126 if ((NULL == client) || (NULL == resp)) {
1127 return UDS_ERR_INVALID_ARG;
1128 }
1129 if (AsResponseSID(UDS_SID_ROUTINE_CONTROL) != client->recv_buf[0]) {
1130 return UDS_ERR_SID_MISMATCH;
1131 }
1132 if (client->recv_size < UDS_0X31_RESP_MIN_LEN) {
1133 return UDS_ERR_RESP_TOO_SHORT;
1134 }
1135 resp->routineControlType = client->recv_buf[1];
1136 resp->routineIdentifier = UnpackBEu16(&client->recv_buf[2]);
1137 resp->routineStatusRecordLength = client->recv_size - UDS_0X31_RESP_MIN_LEN;
1138 resp->routineStatusRecord =
1139 (resp->routineStatusRecordLength == 0U) ? NULL : &client->recv_buf[UDS_0X31_RESP_MIN_LEN];
1140 return UDS_OK;
1141}
1142
1143/**
1144 * @brief Validates and parses server's response to RequestDownload.
1145 *
1146 * @param client
1147 * @param resp
1148 * @return UDSErr_t
1149 * @addtogroup requestDownload_0x34
1150 */
1152 struct RequestDownloadResponse *resp) {
1153 if ((NULL == client) || (NULL == resp)) {
1154 return UDS_ERR_INVALID_ARG;
1155 }
1156 if (AsResponseSID(UDS_SID_REQUEST_DOWNLOAD) != client->recv_buf[0]) {
1157 return UDS_ERR_SID_MISMATCH;
1158 }
1159 if (client->recv_size < UDS_0X34_RESP_BASE_LEN) {
1160 return UDS_ERR_RESP_TOO_SHORT;
1161 }
1162 uint8_t mnrobSize = (client->recv_buf[1] & 0xF0U) >> 4U;
1163 UDS_ASSERT(mnrobSize <= 15U);
1164
1165 if (client->recv_size < (2U + mnrobSize)) {
1166 return UDS_ERR_RESP_TOO_SHORT;
1167 }
1168 resp->maxBlockLength = UnpackBEu32(&client->recv_buf[UDS_0X34_RESP_BASE_LEN], mnrobSize);
1169
1170 return UDS_OK;
1171}
1172
1174 if (NULL == client->fn) {
1175 return UDS_ERR_MISUSE;
1176 }
1177
1178 UDSErr_t err = PollLowLevel(client);
1179
1180 if ((err == UDS_OK) || (err == UDS_NRC_RequestCorrectlyReceived_ResponsePending)) {
1181 ;
1182 } else {
1183 client->fn(client, UDS_EVT_Err, &err);
1184 changeState(client, STATE_IDLE);
1185 }
1186
1187 client->fn(client, UDS_EVT_Poll, NULL);
1188 return err;
1189}
1190
1191UDSErr_t UDSUnpackRDBIResponse(UDSClient_t *client, UDSRDBIVar_t *vars, uint16_t numVars) {
1192 uint16_t offset = UDS_0X22_RESP_BASE_LEN;
1193 if ((client == NULL) || (vars == NULL)) {
1194 return UDS_ERR_INVALID_ARG;
1195 }
1196 for (uint16_t i = 0U; i < numVars; i++) {
1197
1198 if (offset + sizeof(uint16_t) > client->recv_size) {
1199 return UDS_ERR_RESP_TOO_SHORT;
1200 }
1201 uint16_t did = UnpackBEu16(&client->recv_buf[offset]);
1202 if (did != vars[i].did) {
1203 return UDS_ERR_DID_MISMATCH;
1204 }
1205 if ((offset + sizeof(uint16_t) + vars[i].len) > client->recv_size) {
1206 return UDS_ERR_RESP_TOO_SHORT;
1207 }
1208 if (NULL != vars[i].UnpackFn) {
1209 vars[i].UnpackFn(vars[i].data, &client->recv_buf[offset + sizeof(uint16_t)],
1210 vars[i].len);
1211 } else {
1212 return UDS_ERR_INVALID_ARG;
1213 }
1214 offset += sizeof(uint16_t) + vars[i].len;
1215 }
1216 return UDS_OK;
1217}
1218
1219
1220#ifdef UDS_LINES
1221#line 1 "src/server.c"
1222#endif // #ifdef UDS_LINES
1223
1224
1225
1226
1227
1228
1229
1230static inline UDSErr_t NegativeResponse(UDSReq_t *r, const UDSErr_t nrc) {
1231 UDSErr_t ret = nrc;
1232 if ((nrc < UDS_PositiveResponse) || (nrc > UDS_NRC_UNUSED_ISOSAEReserved)) {
1233 UDS_LOGE(__FILE__, "Invalid negative response code: %d (0x%x)", nrc, nrc);
1234 ret = UDS_NRC_GeneralReject;
1235 }
1236
1237 r->send_buf[0] = 0x7FU;
1238 r->send_buf[1] = r->recv_buf[0];
1239 r->send_buf[2] = (uint8_t)ret;
1240 r->send_len = UDS_NEG_RESP_LEN;
1241 return ret;
1242}
1243
1244static inline void NoResponse(UDSReq_t *r) { r->send_len = 0; }
1245
1246static UDSErr_t EmitEvent(UDSServer_t *srv, UDSEvent_t evt, void *data) {
1247 UDSErr_t err = UDS_OK;
1248 if (srv->fn != NULL) {
1249 err = srv->fn(srv, evt, data);
1250 } else {
1251 UDS_LOGI(__FILE__, "Unhandled UDSEvent %d, srv.fn not installed!\n", evt);
1252 err = UDS_NRC_GeneralReject;
1253 }
1254 if (!UDSErrIsNRC(err)) {
1255 UDS_LOGW(__FILE__, "The returned error code %d (0x%x) is not a negative response code", err,
1256 err);
1257 }
1258 return err;
1259}
1260
1261static UDSErr_t Handle_0x10_DiagnosticSessionControl(UDSServer_t *srv, UDSReq_t *r) {
1262 if (r->recv_len < UDS_0X10_REQ_LEN) {
1263 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1264 }
1265
1266 uint8_t sessType = r->recv_buf[1] & 0x7FU;
1267
1268 UDSDiagSessCtrlArgs_t args = {
1269 .type = sessType,
1270 .p2_ms = UDS_CLIENT_DEFAULT_P2_MS,
1271 .p2_star_ms = UDS_CLIENT_DEFAULT_P2_STAR_MS,
1272 };
1273
1274 UDSErr_t err = EmitEvent(srv, UDS_EVT_DiagSessCtrl, &args);
1275
1276 if (UDS_PositiveResponse != err) {
1277 return NegativeResponse(r, err);
1278 }
1279
1280 srv->sessionType = sessType;
1281
1282 switch (sessType) {
1283 case UDS_LEV_DS_DS: // default session
1284 break;
1285 case UDS_LEV_DS_PRGS: // programming session
1286 case UDS_LEV_DS_EXTDS: // extended diagnostic session
1287 default:
1289 break;
1290 }
1291
1292 r->send_buf[0] = AsResponseSID(UDS_SID_DIAGNOSTIC_SESSION_CONTROL);
1293 r->send_buf[1] = sessType;
1294
1295 // UDS-1-2013: Table 29
1296 // resolution: 1ms
1297 PackBE(&r->send_buf[2], args.p2_ms, 2);
1298
1299 // resolution: 10ms
1300 PackBE(&r->send_buf[4], args.p2_star_ms / 10U, 2);
1301
1302 r->send_len = UDS_0X10_RESP_LEN;
1303 return UDS_PositiveResponse;
1304}
1305
1306static UDSErr_t Handle_0x11_ECUReset(UDSServer_t *srv, UDSReq_t *r) {
1307 if (r->recv_len < UDS_0X11_REQ_MIN_LEN) {
1308 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1309 }
1310
1311 uint8_t resetType = r->recv_buf[1] & 0x3FU;
1312
1313 UDSECUResetArgs_t args = {
1314 .type = resetType,
1315 .powerDownTimeMillis = UDS_SERVER_DEFAULT_POWER_DOWN_TIME_MS,
1316 };
1317
1318 UDSErr_t err = EmitEvent(srv, UDS_EVT_EcuReset, &args);
1319
1320 if (UDS_PositiveResponse == err) {
1321 srv->notReadyToReceive = true;
1322 srv->ecuResetScheduled = resetType;
1324 } else {
1325 return NegativeResponse(r, err);
1326 }
1327
1328 r->send_buf[0] = AsResponseSID(UDS_SID_ECU_RESET);
1329 r->send_buf[1] = resetType;
1330
1331 if (UDS_LEV_RT_ERPSD == resetType) {
1332 uint32_t powerDownTime = args.powerDownTimeMillis / 1000U;
1333 if (powerDownTime > 255U) {
1334 powerDownTime = 255U;
1335 }
1336 r->send_buf[2] = powerDownTime & 0xFFU;
1337 r->send_len = UDS_0X11_RESP_BASE_LEN + 1U;
1338 } else {
1339 r->send_len = UDS_0X11_RESP_BASE_LEN;
1340 }
1341 return UDS_PositiveResponse;
1342}
1343
1344static UDSErr_t Handle_0x14_ClearDiagnosticInformation(UDSServer_t *srv, UDSReq_t *r) {
1345 if (r->recv_len < UDS_0X14_REQ_MIN_LEN) {
1346 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1347 }
1348
1349 r->send_buf[0] = AsResponseSID(UDS_SID_CLEAR_DIAGNOSTIC_INFORMATION);
1350 r->send_len = UDS_0X14_RESP_BASE_LEN;
1351
1352 UDSCDIArgs_t args = {
1353 .groupOfDTC = UnpackBEu32(&r->recv_buf[1], 3),
1354 .hasMemorySelection = (r->recv_len >= 5U),
1355 .memorySelection = (r->recv_len >= 5U) ? r->recv_buf[4] : 0U,
1356 };
1357
1358 UDSErr_t err = EmitEvent(srv, UDS_EVT_ClearDiagnosticInfo, &args);
1359
1360 if (err != UDS_PositiveResponse) {
1361 return NegativeResponse(r, err);
1362 }
1363
1364 return UDS_PositiveResponse;
1365}
1366
1367static uint8_t safe_copy(UDSServer_t *srv, const void *src, uint16_t count) {
1368 if (srv == NULL) {
1369 return UDS_NRC_GeneralReject;
1370 }
1371 if (src == NULL) {
1372 return UDS_NRC_GeneralReject;
1373 }
1374 UDSReq_t *r = &srv->r;
1375 if (count <= sizeof(r->send_buf) - r->send_len) {
1376 (void)memmove(&r->send_buf[r->send_len], src, count);
1377 r->send_len += count;
1378 return UDS_PositiveResponse;
1379 }
1380 return UDS_NRC_ResponseTooLong;
1381}
1382
1383static UDSErr_t Handle_0x19_ReadDTCInformation(UDSServer_t *srv, UDSReq_t *r) {
1384 UDSErr_t ret = UDS_PositiveResponse;
1385 uint8_t type = r->recv_buf[1];
1386
1387 if (r->recv_len < UDS_0X19_REQ_MIN_LEN) {
1388 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1389 }
1390
1391 /* Shared by all SubFunc */
1392 r->send_buf[0] = AsResponseSID(UDS_SID_READ_DTC_INFORMATION);
1393 r->send_buf[1] = type;
1394 r->send_len = UDS_0X19_RESP_BASE_LEN;
1395
1396 UDSRDTCIArgs_t args = {
1397 .type = type,
1398 .copy = safe_copy,
1399 };
1400
1401 /* Before checks and emitting Request */
1402 switch (type) {
1403 case 0x01: /* reportNumberOfDTCByStatusMask */
1404 if (r->recv_len < (UDS_0X19_REQ_MIN_LEN + 1U)) {
1405 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1406 }
1407
1408 args.subFuncArgs.numOfDTCByStatusMaskArgs.mask = r->recv_buf[2];
1409 break;
1410 case 0x02: /* reportDTCByStatusMask */
1411 if (r->recv_len < (UDS_0X19_REQ_MIN_LEN + 1U)) {
1412 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1413 }
1414
1415 args.subFuncArgs.dtcStatusByMaskArgs.mask = r->recv_buf[2];
1416 break;
1417 case 0x03: /* reportDTCSnapshotIdentification */
1418 case 0x0A: /* reportSupportedDTC */
1419 case 0x0B: /* reportFirstTestFailedDTC */
1420 case 0x0C: /* reportFirstConfirmedDTC */
1421 case 0x0D: /* reportMostRecentTestFailedDTC */
1422 case 0x0E: /* reportMostRecentConfirmedDTC */
1423 case 0x14: /* reportDTCFaultDetectionCounter */
1424 case 0x15: /* reportDTCWithPermanentStatus */
1425 /* has no subfunction specific args */
1426 break;
1427 case 0x04: /* reportDTCSnapshotRecordByDTCNumber */
1428 if (r->recv_len < (UDS_0X19_REQ_MIN_LEN + 4U)) {
1429 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1430 }
1431
1432 args.subFuncArgs.dtcSnapshotRecordbyDTCNumArgs.dtc = UnpackBEu32(&r->recv_buf[2], 3);
1433 args.subFuncArgs.dtcSnapshotRecordbyDTCNumArgs.snapshotNum = r->recv_buf[5];
1434 break;
1435 case 0x05: /* reportDTCStoredDataByRecordNumber */
1436 case 0x16: /* reportDTCExtDataRecordByNumber */
1437 case 0x1A: /* reportDTCExtendedDataRecordIdentification */
1438 if (r->recv_len < (UDS_0X19_REQ_MIN_LEN + 1U)) {
1439 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1440 }
1441
1442 args.subFuncArgs.dtcStoredDataByRecordNumArgs.recordNum = r->recv_buf[2];
1443 break;
1444 case 0x06: /* reportDTCExtDataRecordByDTCNumber */
1445 if (r->recv_len < (UDS_0X19_REQ_MIN_LEN + 4U)) {
1446 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1447 }
1448
1449 args.subFuncArgs.dtcExtDtaRecordByDTCNumArgs.dtc = UnpackBEu32(&r->recv_buf[2], 3);
1450 args.subFuncArgs.dtcExtDtaRecordByDTCNumArgs.extDataRecNum = r->recv_buf[5];
1451 break;
1452 case 0x07: /* reportNumberOfDTCBySeverityMaskRecord */
1453 case 0x08: /* reportDTCBySeverityMaskRecord */
1454 if (r->recv_len < (UDS_0X19_REQ_MIN_LEN + 2U)) {
1455 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1456 }
1457
1458 args.subFuncArgs.numOfDTCBySeverityMaskArgs.severityMask = r->recv_buf[2];
1459 args.subFuncArgs.numOfDTCBySeverityMaskArgs.statusMask = r->recv_buf[3];
1460 break;
1461 case 0x09: /* reportSeverityInformationOfDTC */
1462 if (r->recv_len < (UDS_0X19_REQ_MIN_LEN + 1U)) {
1463 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1464 }
1465
1466 args.subFuncArgs.severityInfoOfDTCArgs.dtc = UnpackBEu32(&r->recv_buf[2], 3);
1467 break;
1468 case 0x17: /* reportUserDefMemoryDTCByStatusMask */
1469 if (r->recv_len < (UDS_0X19_REQ_MIN_LEN + 2U)) {
1470 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1471 }
1472
1473 args.subFuncArgs.userDefMemoryDTCByStatusMaskArgs.mask = r->recv_buf[2];
1474 args.subFuncArgs.userDefMemoryDTCByStatusMaskArgs.memory = r->recv_buf[3];
1475 break;
1476 case 0x18: /* reportUserDefMemoryDTCSnapshotRecordByDTCNumber */
1477 if (r->recv_len < (UDS_0X19_REQ_MIN_LEN + 5U)) {
1478 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1479 }
1480
1481 args.subFuncArgs.userDefMemDTCSnapshotRecordByDTCNumArgs.dtc =
1482 UnpackBEu32(&r->recv_buf[2], 3);
1483 args.subFuncArgs.userDefMemDTCSnapshotRecordByDTCNumArgs.snapshotNum = r->recv_buf[5];
1484 args.subFuncArgs.userDefMemDTCSnapshotRecordByDTCNumArgs.memory = r->recv_buf[6];
1485 break;
1486 case 0x19: /* reportUserDefMemoryDTCExtDataRecordByDTCNumber */
1487 if (r->recv_len < (UDS_0X19_REQ_MIN_LEN + 5U)) {
1488 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1489 }
1490
1491 args.subFuncArgs.userDefMemDTCExtDataRecordByDTCNumArgs.dtc =
1492 UnpackBEu32(&r->recv_buf[2], 3);
1493 args.subFuncArgs.userDefMemDTCExtDataRecordByDTCNumArgs.extDataRecNum = r->recv_buf[5];
1494 args.subFuncArgs.userDefMemDTCExtDataRecordByDTCNumArgs.memory = r->recv_buf[6];
1495 break;
1496 case 0x42: /* reportWWHOBDDTCByMaskRecord */
1497 if (r->recv_len < (UDS_0X19_REQ_MIN_LEN + 3U)) {
1498 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1499 }
1500
1501 args.subFuncArgs.wwhobdDTCByMaskArgs.functionalGroup = r->recv_buf[2];
1502 args.subFuncArgs.wwhobdDTCByMaskArgs.statusMask = r->recv_buf[3];
1503 args.subFuncArgs.wwhobdDTCByMaskArgs.severityMask = r->recv_buf[4];
1504 break;
1505 case 0x55: /* reportWWHOBDDTCWithPermanentStatus */
1506 if (r->recv_len < (UDS_0X19_REQ_MIN_LEN + 1U)) {
1507 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1508 }
1509
1510 args.subFuncArgs.wwhobdDTCWithPermStatusArgs.functionalGroup = r->recv_buf[2];
1511 break;
1512 case 0x56: /* reportDTCInformationByDTCReadinessGroupIdentifier */
1513 if (r->recv_len < (UDS_0X19_REQ_MIN_LEN + 2U)) {
1514 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1515 }
1516
1517 args.subFuncArgs.dtcInfoByDTCReadinessGroupIdArgs.functionalGroup = r->recv_buf[2];
1518 args.subFuncArgs.dtcInfoByDTCReadinessGroupIdArgs.readinessGroup = r->recv_buf[3];
1519 break;
1520 default:
1521 return NegativeResponse(r, UDS_NRC_SubFunctionNotSupported);
1522 }
1523
1524 ret = EmitEvent(srv, UDS_EVT_ReadDTCInformation, &args);
1525
1526 if (UDS_PositiveResponse != ret) {
1527 return NegativeResponse(r, ret);
1528 }
1529
1530 if (r->send_len < UDS_0X19_RESP_BASE_LEN) {
1531 goto respond_to_0x19_malformed_response;
1532 }
1533
1534 /* subfunc specific reply len checks */
1535 switch (type) {
1536 case 0x01: /* reportNumberOfDTCByStatusMask */
1537 case 0x07: /* reportNumberOfDTCBySeverityMaskRecord */
1538 if (r->send_len != (UDS_0X19_RESP_BASE_LEN + 4U)) {
1539 goto respond_to_0x19_malformed_response;
1540 }
1541 break;
1542 case 0x02: /* reportDTCByStatusMask */
1543 case 0x0A: /* reportSupportedDTC */
1544 case 0x0B: /* reportFirstTestFailedDTC */
1545 case 0x0C: /* reportFirstConfirmedDTC */
1546 case 0x0D: /* reportMostRecentTestFailedDTC */
1547 case 0x0E: /* reportMostRecentConfirmedDTC */
1548 case 0x15: /* reportDTCWithPermanentStatus */
1549 if ((r->send_len < (UDS_0X19_RESP_BASE_LEN + 1U)) ||
1550 ((r->send_len > (UDS_0X19_RESP_BASE_LEN + 1U)) &&
1551 (((r->send_len - UDS_0X19_RESP_BASE_LEN - 1U) % 4U) != 0U))) {
1552 goto respond_to_0x19_malformed_response;
1553 }
1554 break;
1555 case 0x03: /* reportDTCSnapshotIdentification */
1556 case 0x14: /* reportDTCFaultDetectionCounter */
1557 if (((r->send_len - UDS_0X19_RESP_BASE_LEN) % 4U) != 0U) {
1558 goto respond_to_0x19_malformed_response;
1559 }
1560 break;
1561 case 0x04: /* reportDTCSnapshotRecordByDTCNumber */
1562 case 0x06: /* reportDTCExtDataRecordByDTCNumber */
1563 if (r->send_len < (UDS_0X19_RESP_BASE_LEN + 4U)) {
1564 goto respond_to_0x19_malformed_response;
1565 }
1566 break;
1567 case 0x05: /* reportDTCStoredDataByRecordNumber */
1568 case 0x16: /* reportDTCExtDataRecordByNumber */
1569 if (r->send_len < (UDS_0X19_RESP_BASE_LEN + 1U)) {
1570 goto respond_to_0x19_malformed_response;
1571 }
1572 break;
1573 case 0x08: /* reportDTCBySeverityMaskRecord */
1574 case 0x09: /* reportSeverityInformationOfDTC */
1575 if ((r->send_len < (UDS_0X19_RESP_BASE_LEN + 1U)) ||
1576 ((r->send_len > (UDS_0X19_RESP_BASE_LEN + 1U)) &&
1577 (((r->send_len - UDS_0X19_RESP_BASE_LEN - 1U) % 6U) != 0U))) {
1578 goto respond_to_0x19_malformed_response;
1579 }
1580 break;
1581 case 0x17: /* reportUserDefMemoryDTCByStatusMask */
1582 if (r->send_len < (UDS_0X19_RESP_BASE_LEN + 2U) ||
1583 ((r->send_len > (UDS_0X19_RESP_BASE_LEN + 2U)) &&
1584 (((r->send_len - UDS_0X19_RESP_BASE_LEN + 2U) % 4U) != 0U))) {
1585 goto respond_to_0x19_malformed_response;
1586 }
1587 break;
1588 case 0x18: /* reportUserDefMemoryDTCSnapshotRecordByDTCNumber */
1589 case 0x19: /* reportUserDefMemoryDTCExtDataRecordByDTCNumber */
1590 if (r->send_len < (UDS_0X19_RESP_BASE_LEN + 5U)) {
1591 goto respond_to_0x19_malformed_response;
1592 }
1593 break;
1594 case 0x1A: /* reportDTCExtendedDataRecordIdentification */
1595 if ((r->send_len < (UDS_0X19_RESP_BASE_LEN + 1U)) ||
1596 ((r->send_len != (UDS_0X19_RESP_BASE_LEN + 6U)) &&
1597 (r->send_len > (UDS_0X19_RESP_BASE_LEN + 1U)) &&
1598 (r->send_len < (UDS_0X19_RESP_BASE_LEN + 4U))) ||
1599 ((r->send_len > (UDS_0X19_RESP_BASE_LEN + 6U)) &&
1600 (((r->send_len - UDS_0X19_RESP_BASE_LEN + 6U) % 4U) != 0U))) {
1601 goto respond_to_0x19_malformed_response;
1602 }
1603 break;
1604 case 0x42: /* reportWWHOBDDTCByMaskRecord */
1605 if (r->send_len < (UDS_0X19_RESP_BASE_LEN + 4U) ||
1606 ((r->send_len > (UDS_0X19_RESP_BASE_LEN + 4U)) &&
1607 (((r->send_len - UDS_0X19_RESP_BASE_LEN - 4U) % 5U) != 0U))) {
1608 goto respond_to_0x19_malformed_response;
1609 }
1610 break;
1611 case 0x55: /* reportWWHOBDDTCWithPermanentStatus */
1612 if ((r->send_len < (UDS_0X19_RESP_BASE_LEN + 3U)) ||
1613 ((r->send_len > (UDS_0X19_RESP_BASE_LEN + 3U)) &&
1614 (((r->send_len - UDS_0X19_RESP_BASE_LEN - 3U) % 4U) != 0U))) {
1615 goto respond_to_0x19_malformed_response;
1616 }
1617 break;
1618 case 0x56: /* reportDTCInformationByDTCReadinessGroupIdentifier */
1619 if ((r->send_len < (UDS_0X19_RESP_BASE_LEN + 4U)) ||
1620 ((r->send_len > (UDS_0X19_RESP_BASE_LEN + 4U)) &&
1621 (((r->send_len - UDS_0X19_RESP_BASE_LEN + 4U) % 4U) != 0U))) {
1622 goto respond_to_0x19_malformed_response;
1623 }
1624 break;
1625 default:
1626 UDS_LOGW(__FILE__, "RDTCI subFunc 0x%02X is not supported.\n", type);
1627 return NegativeResponse(r, UDS_NRC_SubFunctionNotSupported);
1628 }
1629
1630 return UDS_PositiveResponse;
1631respond_to_0x19_malformed_response:
1632 UDS_LOGE(__FILE__, "RDTCI subFunc 0x%02X is malformed. Length: %zu\n", type, r->send_len);
1633 return NegativeResponse(r, UDS_NRC_GeneralReject);
1634}
1635
1636static UDSErr_t Handle_0x22_ReadDataByIdentifier(UDSServer_t *srv, UDSReq_t *r) {
1637 if (0U != (r->recv_len - 1U) % sizeof(uint16_t)) {
1638 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1639 }
1640
1641 const uint8_t numDIDs = (uint8_t)(r->recv_len / sizeof(uint16_t));
1642
1643 if (0U == numDIDs) {
1644 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1645 }
1646
1647 r->send_buf[0] = AsResponseSID(UDS_SID_READ_DATA_BY_IDENTIFIER);
1648 r->send_len = 1;
1649
1650 for (uint16_t did = 0; did < numDIDs; did++) {
1651 uint16_t idx = (uint16_t)(1U + (did * 2U));
1652 uint16_t dataId = UnpackBEu16(&r->recv_buf[idx]);
1653
1654 if ((r->send_len + 3U) > sizeof(r->send_buf)) {
1655 return NegativeResponse(r, UDS_NRC_ResponseTooLong);
1656 }
1657 PackBE(&r->send_buf[r->send_len], dataId, 2);
1658 r->send_len += 2U;
1659
1660 UDSRDBIArgs_t args = {
1661 .dataId = dataId,
1662 .copy = safe_copy,
1663 };
1664
1665 const size_t send_len_before = r->send_len;
1666 UDSErr_t ret = EmitEvent(srv, UDS_EVT_ReadDataByIdent, &args);
1667
1668 // r->send_len is modified when the user calls safe_copy.
1669 /* cppcheck-suppress [knownConditionTrueFalse] */
1670 if ((UDS_PositiveResponse == ret) && (send_len_before == r->send_len)) {
1671 UDS_LOGE(__FILE__, "RDBI response positive but no data sent\n");
1672 return NegativeResponse(r, UDS_NRC_GeneralReject);
1673 }
1674
1675 if (UDS_PositiveResponse != ret) {
1676 return NegativeResponse(r, ret);
1677 }
1678 }
1679 return UDS_PositiveResponse;
1680}
1681
1682/**
1683 * @brief decodes addressAndLength at a nonzero offset within the receive buffer.
1684 * @see ISO 14229-1:2020(E) Annex H
1685 *
1686 * @param r request buffer
1687 * @param buf pointer to addressAndDataLengthFormatIdentifier in recv_buf
1688 * @param memoryAddress the decoded memory address
1689 * @param memorySize the decoded memory size
1690 * @param offset how many elements (addres and size pairs) away from the format identifier
1691 * @return UDSErr_t
1692 */
1693static UDSErr_t decodeAddressAndLengthAt(UDSReq_t *r, uint8_t *const buf, uintptr_t *memoryAddress,
1694 size_t *memorySize, size_t offset) {
1695 UDS_ASSERT(r);
1696 UDS_ASSERT(memoryAddress);
1697 UDS_ASSERT(memorySize);
1698 *memoryAddress = 0;
1699 *memorySize = 0;
1700
1701 if (r->recv_len < 3U) {
1702 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1703 }
1704
1705 const uint8_t memorySizeLength = (buf[0] & 0xF0U) >> 4U;
1706 const uint8_t memoryAddressLength = buf[0] & 0x0FU;
1707
1708 if ((memorySizeLength == 0U) || (memorySizeLength > sizeof(size_t))) {
1709 return NegativeResponse(r, UDS_NRC_RequestOutOfRange);
1710 }
1711
1712 if ((memoryAddressLength == 0U) || (memoryAddressLength > sizeof(size_t))) {
1713 return NegativeResponse(r, UDS_NRC_RequestOutOfRange);
1714 }
1715
1716 const size_t offsetBytes = offset * ((size_t)memoryAddressLength + (size_t)memorySizeLength);
1717
1718 if ((1U + offsetBytes + memorySizeLength + memoryAddressLength) > r->recv_len) {
1719 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1720 }
1721
1722 *memoryAddress = UnpackBEuintptr(&buf[1U + offsetBytes], memoryAddressLength);
1723 *memorySize = UnpackBEsize(&buf[1U + offsetBytes + memoryAddressLength], memorySizeLength);
1724
1725 return UDS_PositiveResponse;
1726}
1727
1728/**
1729 * @brief decode the addressAndLengthFormatIdentifier
1730 *
1731 * @param srv
1732 * @param buf pointer to addressAndDataLengthFormatIdentifier in recv_buf
1733 * @param memoryAddress the decoded memory address
1734 * @param memorySize the decoded memory size
1735 * @return uint8_t
1736 */
1737static UDSErr_t decodeAddressAndLength(UDSReq_t *r, uint8_t *const buf, uintptr_t *memoryAddress,
1738 size_t *memorySize) {
1739 return decodeAddressAndLengthAt(r, buf, memoryAddress, memorySize, 0);
1740}
1741
1742static UDSErr_t Handle_0x23_ReadMemoryByAddress(UDSServer_t *srv, UDSReq_t *r) {
1743 UDSErr_t ret = UDS_PositiveResponse;
1744 uintptr_t address = 0;
1745 size_t length = 0;
1746
1747 if (r->recv_len < UDS_0X23_REQ_MIN_LEN) {
1748 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1749 }
1750
1751 ret = decodeAddressAndLength(r, &r->recv_buf[1], &address, &length);
1752 if (UDS_PositiveResponse != ret) {
1753 return NegativeResponse(r, ret);
1754 }
1755
1756 UDSReadMemByAddrArgs_t args = {
1757 .memAddr = address,
1758 .memSize = length,
1759 .copy = safe_copy,
1760 };
1761
1762 r->send_buf[0] = AsResponseSID(UDS_SID_READ_MEMORY_BY_ADDRESS);
1763 r->send_len = UDS_0X23_RESP_BASE_LEN;
1764 ret = EmitEvent(srv, UDS_EVT_ReadMemByAddr, &args);
1765 if (UDS_PositiveResponse != ret) {
1766 return NegativeResponse(r, ret);
1767 }
1768 if (r->send_len != (UDS_0X23_RESP_BASE_LEN + length)) {
1769 UDS_LOGE(__FILE__, "response positive but not all data sent: expected %zu, sent %zu",
1770 length, r->send_len - UDS_0X23_RESP_BASE_LEN);
1771 return NegativeResponse(r, UDS_NRC_GeneralReject);
1772 }
1773 return UDS_PositiveResponse;
1774}
1775
1776static UDSErr_t Handle_0x27_SecurityAccess(UDSServer_t *srv, UDSReq_t *r) {
1777 if (r->recv_len < UDS_0X27_REQ_BASE_LEN) {
1778 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1779 }
1780
1781 if (!UDSTimeAfter(UDSMillis(), srv->sec_access_boot_delay_timer)) {
1782 return NegativeResponse(r, UDS_NRC_RequiredTimeDelayNotExpired);
1783 }
1784
1785 if (!UDSTimeAfter(UDSMillis(), srv->sec_access_auth_fail_timer)) {
1786 return NegativeResponse(r, UDS_NRC_ExceedNumberOfAttempts);
1787 }
1788
1789 uint8_t subFunction = r->recv_buf[1];
1790 if (UDSSecurityAccessLevelIsReserved(subFunction)) {
1791 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1792 }
1793
1794 r->send_buf[0] = AsResponseSID(UDS_SID_SECURITY_ACCESS);
1795 r->send_buf[1] = subFunction;
1796 r->send_len = UDS_0X27_RESP_BASE_LEN;
1797
1798 // Even: sendKey
1799 if (0U == (subFunction % 2U)) {
1800 UDS_ASSERT(subFunction >= 2U);
1801 uint8_t requestedLevel = subFunction - 1U;
1803 .level = requestedLevel,
1804 .key = &r->recv_buf[UDS_0X27_REQ_BASE_LEN],
1805 .len = (uint16_t)(r->recv_len - UDS_0X27_REQ_BASE_LEN),
1806 };
1807
1808 UDSErr_t ret = EmitEvent(srv, UDS_EVT_SecAccessValidateKey, &args);
1809
1810 if (UDS_PositiveResponse != ret) {
1813 return NegativeResponse(r, ret);
1814 }
1815
1816 // "requestSeed = 0x01" identifies a fixed relationship between
1817 // "requestSeed = 0x01" and "sendKey = 0x02"
1818 // "requestSeed = 0x03" identifies a fixed relationship between
1819 // "requestSeed = 0x03" and "sendKey = 0x04"
1820 srv->securityLevel = requestedLevel;
1821 r->send_len = UDS_0X27_RESP_BASE_LEN;
1822 return UDS_PositiveResponse;
1823 }
1824
1825 // Odd: requestSeed
1826 UDS_ASSERT(1U == (subFunction % 2U));
1827
1828 // Already unlocked: send a zero seed
1829 if (subFunction == srv->securityLevel) {
1830 // Table 52 sends a response of length 2. Use a preprocessor define if this needs
1831 // customizing by the user.
1832 const uint8_t already_unlocked[] = {0x00, 0x00};
1833 return safe_copy(srv, already_unlocked, sizeof(already_unlocked));
1834 }
1835
1836 // Not yet unlocked: request a seed
1837 UDS_ASSERT(subFunction != srv->securityLevel);
1838
1840 .level = subFunction,
1841 .dataRecord = &r->recv_buf[UDS_0X27_REQ_BASE_LEN],
1842 .len = (uint16_t)(r->recv_len - UDS_0X27_REQ_BASE_LEN),
1843 .copySeed = safe_copy,
1844 };
1845
1846 UDSErr_t ret = EmitEvent(srv, UDS_EVT_SecAccessRequestSeed, &args);
1847
1848 if (UDS_PositiveResponse != ret) {
1849 return NegativeResponse(r, ret);
1850 }
1851
1852 if (r->send_len <= UDS_0X27_RESP_BASE_LEN) { // no data was copied
1853 UDS_LOGE(__FILE__, "0x27: no seed data was copied");
1854 return NegativeResponse(r, UDS_NRC_GeneralReject);
1855 }
1856 return UDS_PositiveResponse;
1857}
1858
1859static UDSErr_t Handle_0x28_CommunicationControl(UDSServer_t *srv, UDSReq_t *r) {
1860 uint8_t controlType = r->recv_buf[1] & 0x7FU;
1861 uint8_t communicationType = r->recv_buf[2];
1862
1863 if (r->recv_len < UDS_0X28_REQ_BASE_LEN) {
1864 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1865 }
1866
1867 UDSCommCtrlArgs_t args = {
1868 .ctrlType = controlType,
1869 .commType = communicationType,
1870 .nodeId = 0,
1871 };
1872
1873 if ((args.ctrlType == 0x04U) || (args.ctrlType == 0x05U)) {
1874 if (r->recv_len < (UDS_0X28_REQ_BASE_LEN + 2U)) {
1875 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1876 }
1877 args.nodeId = UnpackBEu16(&r->recv_buf[3]);
1878 }
1879
1880 UDSErr_t err = EmitEvent(srv, UDS_EVT_CommCtrl, &args);
1881 if (UDS_PositiveResponse != err) {
1882 return NegativeResponse(r, err);
1883 }
1884
1885 r->send_buf[0] = AsResponseSID(UDS_SID_COMMUNICATION_CONTROL);
1886 r->send_buf[1] = controlType;
1887 r->send_len = UDS_0X28_RESP_LEN;
1888 return UDS_PositiveResponse;
1889}
1890
1891static UDSErr_t Handle_0x2C_DynamicDefineDataIdentifier(UDSServer_t *srv, UDSReq_t *r) {
1892 UDSErr_t ret = UDS_PositiveResponse;
1893 uint8_t type = r->recv_buf[1];
1894
1895 if (r->recv_len < UDS_0X2C_REQ_MIN_LEN) {
1896 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1897 }
1898
1899 r->send_buf[0] = AsResponseSID(UDS_SID_DYNAMICALLY_DEFINE_DATA_IDENTIFIER);
1900 r->send_buf[1] = type;
1901 /* Set dynamicDataId. If response does not require it, the length will be adjusted later */
1902 r->send_buf[2] = r->recv_buf[2];
1903 r->send_buf[3] = r->recv_buf[3];
1904 r->send_len = UDS_0X2C_RESP_BASE_LEN + 2U;
1905
1906 UDSDDDIArgs_t args = {
1907 .type = type,
1908 .allDataIds = false,
1909 .dynamicDataId = UnpackBEu16(&r->recv_buf[2]),
1910 };
1911
1912 /* Since the paramter for subFunc 0x01 and 0x02 are dynamic and should not be handled by
1913 * separate events, we need to emit the event for every subfunction separatedly
1914 */
1915 switch (type) {
1916 case 0x01: /* defineByIdentifier */
1917 {
1918 if ((r->recv_len < (UDS_0X2C_REQ_MIN_LEN + 2U + 4U)) ||
1919 (((r->recv_len - (UDS_0X2C_REQ_MIN_LEN + 2U)) % 4U) != 0U)) {
1920 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1921 }
1922
1923 size_t numDIDs = (r->recv_len - 4U) / 4U;
1924
1925 for (size_t i = 0; i < numDIDs; i++) {
1926 args.subFuncArgs.defineById.sourceDataId = UnpackBEu16(&r->recv_buf[4U + (i * 4U)]);
1927 args.subFuncArgs.defineById.position = r->recv_buf[6U + (i * 4U)];
1928 args.subFuncArgs.defineById.size = r->recv_buf[7U + (i * 4U)];
1929
1930 ret = EmitEvent(srv, UDS_EVT_DynamicDefineDataId, &args);
1931
1932 if (UDS_PositiveResponse != ret) {
1933 return NegativeResponse(r, ret);
1934 }
1935 }
1936
1937 return UDS_PositiveResponse;
1938 }
1939 case 0x02: /* defineByMemoryAddress */
1940 {
1941 /* 2 bytes dynamic data id
1942 * 1 byte address and length format identifier
1943 * min 1 byte address
1944 * min 1 byte length
1945 */
1946 if (r->recv_len < (UDS_0X2C_REQ_MIN_LEN + 5U)) {
1947 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1948 }
1949
1950 size_t bytesPerAddrAndSize = ((r->recv_buf[4] & 0xF0U) >> 4U) + (r->recv_buf[4] & 0x0FU);
1951
1952 if (bytesPerAddrAndSize == 0U) {
1953 UDS_LOGW(__FILE__,
1954 "DDDI: define By Memory Address request with invalid "
1955 "AddressAndLengthFormatIdentifier: 0x%02X\n",
1956 r->recv_buf[4]);
1957 return NegativeResponse(r, UDS_NRC_RequestOutOfRange);
1958 }
1959
1960 if (((r->recv_len - 5U) % bytesPerAddrAndSize) != 0U) {
1961 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
1962 }
1963
1964 size_t numAddrs = (r->recv_len - 5U) / bytesPerAddrAndSize;
1965
1966 for (size_t i = 0; i < numAddrs; i++) {
1967 ret = decodeAddressAndLengthAt(r, &r->recv_buf[4],
1968 &args.subFuncArgs.defineByMemAddress.memAddr,
1969 &args.subFuncArgs.defineByMemAddress.memSize, i);
1970
1971 if (UDS_PositiveResponse != ret) {
1972 return NegativeResponse(r, ret);
1973 }
1974
1975 ret = EmitEvent(srv, UDS_EVT_DynamicDefineDataId, &args);
1976
1977 if (UDS_PositiveResponse != ret) {
1978 return NegativeResponse(r, ret);
1979 }
1980 }
1981
1982 return UDS_PositiveResponse;
1983 }
1984
1985 case 0x03: /* clearDynamicallyDefined */
1986 {
1987 if (r->recv_len == UDS_0X2C_REQ_MIN_LEN) {
1988 args.allDataIds = true;
1989 r->send_len = UDS_0X2C_RESP_BASE_LEN;
1990 }
1991
1992 ret = EmitEvent(srv, UDS_EVT_DynamicDefineDataId, &args);
1993 if (UDS_PositiveResponse != ret) {
1994 return NegativeResponse(r, ret);
1995 }
1996
1997 return UDS_PositiveResponse;
1998 }
1999 default:
2000 UDS_LOGW(__FILE__, "Unsupported DDDI subFunc 0x%02X\n", type);
2001 return NegativeResponse(r, UDS_NRC_SubFunctionNotSupported);
2002 }
2003}
2004
2005static UDSErr_t Handle_0x2E_WriteDataByIdentifier(UDSServer_t *srv, UDSReq_t *r) {
2006 uint16_t dataLen = 0;
2007 uint16_t dataId = 0;
2008 UDSErr_t err = UDS_PositiveResponse;
2009
2010 /* UDS-1 2013 Figure 21 Key 1 */
2011 if (r->recv_len < UDS_0X2E_REQ_MIN_LEN) {
2012 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
2013 }
2014
2015 dataId = UnpackBEu16(&r->recv_buf[1]);
2016 dataLen = (uint16_t)(r->recv_len - UDS_0X2E_REQ_BASE_LEN);
2017
2018 UDSWDBIArgs_t args = {
2019 .dataId = dataId,
2020 .data = &r->recv_buf[UDS_0X2E_REQ_BASE_LEN],
2021 .len = dataLen,
2022 };
2023
2024 err = EmitEvent(srv, UDS_EVT_WriteDataByIdent, &args);
2025 if (UDS_PositiveResponse != err) {
2026 return NegativeResponse(r, err);
2027 }
2028
2029 r->send_buf[0] = AsResponseSID(UDS_SID_WRITE_DATA_BY_IDENTIFIER);
2030 PackBE(&r->send_buf[1], dataId, 2);
2031 r->send_len = UDS_0X2E_RESP_LEN;
2032 return UDS_PositiveResponse;
2033}
2034
2035static UDSErr_t Handle_0x2F_IOControlByIdentifier(UDSServer_t *srv, UDSReq_t *r) {
2036 if (r->recv_len < UDS_0X2F_REQ_MIN_LEN) {
2037 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
2038 }
2039
2040 r->send_buf[0] = AsResponseSID(UDS_SID_IO_CONTROL_BY_IDENTIFIER);
2041 r->send_buf[1] = r->recv_buf[1];
2042 r->send_buf[2] = r->recv_buf[2];
2043 r->send_buf[3] = r->recv_buf[3];
2044 r->send_len = UDS_0X2F_RESP_BASE_LEN;
2045
2046 UDSIOCtrlArgs_t args = {
2047 .dataId = UnpackBEu16(&r->recv_buf[1]),
2048 .ioCtrlParam = r->recv_buf[3],
2049 .ctrlStateAndMask = &r->recv_buf[UDS_0X2F_REQ_MIN_LEN],
2050 .ctrlStateAndMaskLen = r->recv_len - UDS_0X2F_REQ_MIN_LEN,
2051 .copy = safe_copy,
2052 };
2053
2054 UDSErr_t err = EmitEvent(srv, UDS_EVT_IOControl, &args);
2055
2056 if (err != UDS_PositiveResponse) {
2057 return NegativeResponse(r, err);
2058 }
2059
2060 return UDS_PositiveResponse;
2061}
2062
2063static UDSErr_t Handle_0x31_RoutineControl(UDSServer_t *srv, UDSReq_t *r) {
2064 UDSErr_t err = UDS_PositiveResponse;
2065 if (r->recv_len < UDS_0X31_REQ_MIN_LEN) {
2066 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
2067 }
2068
2069 uint8_t routineControlType = r->recv_buf[1] & 0x7FU;
2070 uint16_t routineIdentifier = UnpackBEu16(&r->recv_buf[2]);
2071
2072 UDSRoutineCtrlArgs_t args = {
2073 .ctrlType = routineControlType,
2074 .id = routineIdentifier,
2075 .optionRecord = &r->recv_buf[UDS_0X31_REQ_MIN_LEN],
2076 .len = (uint16_t)(r->recv_len - UDS_0X31_REQ_MIN_LEN),
2077 .copyStatusRecord = safe_copy,
2078 };
2079
2080 r->send_buf[0] = AsResponseSID(UDS_SID_ROUTINE_CONTROL);
2081 r->send_buf[1] = routineControlType;
2082 PackBE(&r->send_buf[2], routineIdentifier, 2);
2083 r->send_len = UDS_0X31_RESP_MIN_LEN;
2084
2085 switch (routineControlType) {
2086 case UDS_LEV_RCTP_STR: // start routine
2087 case UDS_LEV_RCTP_STPR: // stop routine
2088 case UDS_LEV_RCTP_RRR: // request routine results
2089 err = EmitEvent(srv, UDS_EVT_RoutineCtrl, &args);
2090 if (UDS_PositiveResponse != err) {
2091 return NegativeResponse(r, err);
2092 }
2093 break;
2094 default:
2095 return NegativeResponse(r, UDS_NRC_RequestOutOfRange);
2096 }
2097 return UDS_PositiveResponse;
2098}
2099
2100static void ResetTransfer(UDSServer_t *srv) {
2101 UDS_ASSERT(srv);
2102 srv->xferBlockSequenceCounter = 1;
2103 srv->xferByteCounter = 0;
2104 srv->xferTotalBytes = 0;
2105 srv->xferIsActive = false;
2106}
2107
2108static void BeginTransfer(UDSServer_t *srv, size_t xferTotalBytes, size_t xferBlockLength) {
2109 UDS_ASSERT(srv);
2110 srv->xferBlockSequenceCounter = 1;
2111 srv->xferByteCounter = 0;
2112 srv->xferTotalBytes = xferTotalBytes;
2113 srv->xferBlockLength = xferBlockLength;
2114 srv->xferIsActive = true;
2115}
2116
2117static UDSErr_t Handle_0x34_RequestDownload(UDSServer_t *srv, UDSReq_t *r) {
2118 UDSErr_t err = UDS_PositiveResponse;
2119 uintptr_t memoryAddress = 0;
2120 size_t memorySize = 0;
2121
2122 if (srv->xferIsActive) {
2123 return NegativeResponse(r, UDS_NRC_ConditionsNotCorrect);
2124 }
2125
2126 if (r->recv_len < UDS_0X34_REQ_BASE_LEN) {
2127 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
2128 }
2129
2130 err = decodeAddressAndLength(r, &r->recv_buf[2], &memoryAddress, &memorySize);
2131 if (UDS_PositiveResponse != err) {
2132 return NegativeResponse(r, err);
2133 }
2134
2136 .addr = memoryAddress,
2137 .size = memorySize,
2138 .dataFormatIdentifier = r->recv_buf[1],
2139 .maxNumberOfBlockLength = UDS_SERVER_DEFAULT_XFER_DATA_MAX_BLOCKLENGTH,
2140 };
2141
2142 err = EmitEvent(srv, UDS_EVT_RequestDownload, &args);
2143
2144 if (args.maxNumberOfBlockLength < 3U) {
2145 UDS_LOGE(__FILE__, "maxNumberOfBlockLength too short");
2146 return NegativeResponse(r, UDS_NRC_GeneralReject);
2147 }
2148
2149 if (UDS_PositiveResponse != err) {
2150 return NegativeResponse(r, err);
2151 }
2152
2153 BeginTransfer(srv, memorySize, args.maxNumberOfBlockLength);
2154
2155 // ISO-14229-1:2013 Table 401:
2156 uint8_t lengthFormatIdentifier = (uint8_t)(sizeof(args.maxNumberOfBlockLength) << 4U);
2157
2158 /* ISO-14229-1:2013 Table 396: maxNumberOfBlockLength
2159 This parameter is used by the requestDownload positive response message to
2160 inform the client how many data bytes (maxNumberOfBlockLength) to include in
2161 each TransferData request message from the client. This length reflects the
2162 complete message length, including the service identifier and the
2163 data-parameters present in the TransferData request message.
2164 */
2167 }
2168
2169 r->send_buf[0] = AsResponseSID(UDS_SID_REQUEST_DOWNLOAD);
2170 r->send_buf[1] = lengthFormatIdentifier;
2171 enum { N = 2 };
2172 static_assert(sizeof(args.maxNumberOfBlockLength) == N, "See ISO14229-1:2020 Table 442");
2173 PackBE(&r->send_buf[2], args.maxNumberOfBlockLength, N);
2174 r->send_len = UDS_0X34_RESP_BASE_LEN + N;
2175 return UDS_PositiveResponse;
2176}
2177
2178static UDSErr_t Handle_0x35_RequestUpload(UDSServer_t *srv, UDSReq_t *r) {
2179 UDSErr_t err = UDS_PositiveResponse;
2180 uintptr_t memoryAddress = 0;
2181 size_t memorySize = 0;
2182
2183 if (srv->xferIsActive) {
2184 return NegativeResponse(r, UDS_NRC_ConditionsNotCorrect);
2185 }
2186
2187 if (r->recv_len < UDS_0X35_REQ_BASE_LEN) {
2188 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
2189 }
2190
2191 err = decodeAddressAndLength(r, &r->recv_buf[2], &memoryAddress, &memorySize);
2192 if (UDS_PositiveResponse != err) {
2193 return NegativeResponse(r, err);
2194 }
2195
2196 UDSRequestUploadArgs_t args = {
2197 .addr = memoryAddress,
2198 .size = memorySize,
2199 .dataFormatIdentifier = r->recv_buf[1],
2200 .maxNumberOfBlockLength = UDS_SERVER_DEFAULT_XFER_DATA_MAX_BLOCKLENGTH,
2201 };
2202
2203 err = EmitEvent(srv, UDS_EVT_RequestUpload, &args);
2204
2205 if (args.maxNumberOfBlockLength < 3U) {
2206 UDS_LOGE(__FILE__, "maxNumberOfBlockLength too short");
2207 return NegativeResponse(r, UDS_NRC_GeneralReject);
2208 }
2209
2210 if (UDS_PositiveResponse != err) {
2211 return NegativeResponse(r, err);
2212 }
2213
2214 BeginTransfer(srv, memorySize, args.maxNumberOfBlockLength);
2215
2216 uint8_t lengthFormatIdentifier = (uint8_t)(sizeof(args.maxNumberOfBlockLength) << 4U);
2217
2218 r->send_buf[0] = AsResponseSID(UDS_SID_REQUEST_UPLOAD);
2219 r->send_buf[1] = lengthFormatIdentifier;
2220 PackBE(&r->send_buf[UDS_0X35_RESP_BASE_LEN], args.maxNumberOfBlockLength,
2221 sizeof(args.maxNumberOfBlockLength));
2222 r->send_len = UDS_0X35_RESP_BASE_LEN + (size_t)sizeof(args.maxNumberOfBlockLength);
2223 return UDS_PositiveResponse;
2224}
2225
2226static UDSErr_t Handle_0x36_TransferData(UDSServer_t *srv, UDSReq_t *r) {
2227 UDSErr_t err = UDS_PositiveResponse;
2228 uint8_t blockSequenceCounter = 0;
2229
2230 if (!srv->xferIsActive) {
2231 return NegativeResponse(r, UDS_NRC_UploadDownloadNotAccepted);
2232 }
2233
2234 if (r->recv_len < UDS_0X36_REQ_BASE_LEN) {
2235 err = UDS_NRC_IncorrectMessageLengthOrInvalidFormat;
2236 goto fail;
2237 }
2238
2239 uint16_t request_data_len = (uint16_t)(r->recv_len - UDS_0X36_REQ_BASE_LEN);
2240 blockSequenceCounter = r->recv_buf[1];
2241
2242 if (!srv->RCRRP) {
2243 if (blockSequenceCounter != srv->xferBlockSequenceCounter) {
2244 err = UDS_NRC_RequestSequenceError;
2245 goto fail;
2246 } else {
2248 }
2249 }
2250
2251 if ((srv->xferByteCounter + request_data_len) > srv->xferTotalBytes) {
2252 err = UDS_NRC_TransferDataSuspended;
2253 goto fail;
2254 }
2255
2256 {
2257 UDSTransferDataArgs_t args = {
2258 .data = &r->recv_buf[UDS_0X36_REQ_BASE_LEN],
2259 .len = (uint16_t)(r->recv_len - UDS_0X36_REQ_BASE_LEN),
2260 .maxRespLen = (uint16_t)(srv->xferBlockLength - UDS_0X36_RESP_BASE_LEN),
2261 .copyResponse = safe_copy,
2262 };
2263
2264 r->send_buf[0] = AsResponseSID(UDS_SID_TRANSFER_DATA);
2265 r->send_buf[1] = blockSequenceCounter;
2266 r->send_len = UDS_0X36_RESP_BASE_LEN;
2267
2268 err = EmitEvent(srv, UDS_EVT_TransferData, &args);
2269
2270 if (err == UDS_PositiveResponse) {
2271 srv->xferByteCounter += request_data_len;
2272 return UDS_PositiveResponse;
2273 }
2274 if (err == UDS_NRC_RequestCorrectlyReceived_ResponsePending) {
2275 return NegativeResponse(r, UDS_NRC_RequestCorrectlyReceived_ResponsePending);
2276 }
2277 goto fail;
2278 }
2279
2280fail:
2281 ResetTransfer(srv);
2282 return NegativeResponse(r, err);
2283}
2284
2285static UDSErr_t Handle_0x37_RequestTransferExit(UDSServer_t *srv, UDSReq_t *r) {
2286 UDSErr_t err = UDS_PositiveResponse;
2287
2288 if (!srv->xferIsActive) {
2289 return NegativeResponse(r, UDS_NRC_UploadDownloadNotAccepted);
2290 }
2291
2292 r->send_buf[0] = AsResponseSID(UDS_SID_REQUEST_TRANSFER_EXIT);
2293 r->send_len = UDS_0X37_RESP_BASE_LEN;
2294
2296 .data = &r->recv_buf[UDS_0X37_REQ_BASE_LEN],
2297 .len = (uint16_t)(r->recv_len - UDS_0X37_REQ_BASE_LEN),
2298 .copyResponse = safe_copy,
2299 };
2300
2301 err = EmitEvent(srv, UDS_EVT_RequestTransferExit, &args);
2302
2303 if (err == UDS_PositiveResponse) {
2304 ResetTransfer(srv);
2305 return UDS_PositiveResponse;
2306 }
2307 if (err == UDS_NRC_RequestCorrectlyReceived_ResponsePending) {
2308 return NegativeResponse(r, UDS_NRC_RequestCorrectlyReceived_ResponsePending);
2309 }
2310 ResetTransfer(srv);
2311 return NegativeResponse(r, err);
2312}
2313
2314static UDSErr_t Handle_0x38_RequestFileTransfer(UDSServer_t *srv, UDSReq_t *r) {
2315
2316 if (srv->xferIsActive) {
2317 return UDS_NRC_ConditionsNotCorrect;
2318 }
2319 if (r->recv_len < UDS_0X38_REQ_BASE_LEN) {
2320 return UDS_NRC_IncorrectMessageLengthOrInvalidFormat;
2321 }
2322
2323 const uint8_t mode_of_operation = r->recv_buf[1];
2324
2325 if ((mode_of_operation < UDS_MOOP_ADDFILE) || (mode_of_operation > UDS_MOOP_RSFILE)) {
2326 return UDS_NRC_IncorrectMessageLengthOrInvalidFormat;
2327 }
2328
2329 const uint16_t file_path_len = UnpackBEu16(&r->recv_buf[2]);
2330 uint8_t data_format_identifier = 0;
2331 size_t file_size_uncompressed = 0;
2332 size_t file_size_compressed = 0;
2333 size_t byte_idx = 4U + (size_t)file_path_len;
2334
2335 if (byte_idx > r->recv_len) {
2336 return UDS_NRC_IncorrectMessageLengthOrInvalidFormat;
2337 }
2338
2339 if ((mode_of_operation == UDS_MOOP_DELFILE) || (mode_of_operation == UDS_MOOP_RDDIR)) {
2340 // ISO14229:2020 Table 481:
2341 // If the modeOfOperation parameter equals to 0x02 (DeleteFile) and 0x05 (ReadDir) this
2342 // parameter [dataFormatIdentifier] shall not be included in the request message.
2343 } else {
2344 data_format_identifier = r->recv_buf[byte_idx];
2345 byte_idx++;
2346 }
2347
2348 if ((mode_of_operation == UDS_MOOP_DELFILE) || (mode_of_operation == UDS_MOOP_RDFILE) ||
2349 (mode_of_operation == UDS_MOOP_RDDIR)) {
2350 // Paraphrasing ISO14229:2020 Table 481:
2351 // If the modeOfOperation parameter equals to 0x02 (DeleteFile), 0x04 (ReadFile) or 0x05
2352 // (ReadDir) these parameters [fileSizeParameterLength, fileSizeUncompressed,
2353 // fileSizeCompressed] shall not be included in the request message.
2354 } else {
2355 // also called "k" in ISO14229:2020
2356 const uint8_t file_size_parameter_length = r->recv_buf[byte_idx];
2357 byte_idx++;
2358
2359 static_assert(sizeof(file_size_uncompressed) == sizeof(file_size_compressed),
2360 "Both should be k-byte numbers per Table 480");
2361 if (file_size_parameter_length > sizeof(file_size_compressed)) {
2362 return UDS_NRC_RequestOutOfRange;
2363 }
2364 // the remaining two request fields (fileSizeUncompressed and fileSizeCompressed) are each
2365 // file_size_parameter_length (k) bytes long
2366 if ((byte_idx + (2U * (size_t)file_size_parameter_length)) > r->recv_len) {
2367 return UDS_NRC_RequestOutOfRange;
2368 }
2369 for (uint8_t i = 0; i < file_size_parameter_length; i++) {
2370 uint8_t data_byte = r->recv_buf[byte_idx];
2371 uint8_t shift_by_bytes = (uint8_t)(file_size_parameter_length - i - 1U);
2372 file_size_uncompressed |= (size_t)data_byte << (8U * (size_t)shift_by_bytes);
2373 byte_idx++;
2374 }
2375 for (uint8_t i = 0; i < file_size_parameter_length; i++) {
2376 uint8_t data_byte = r->recv_buf[byte_idx];
2377 uint8_t shift_by_bytes = (uint8_t)(file_size_parameter_length - i - 1U);
2378 file_size_compressed |= (size_t)data_byte << (8U * (size_t)shift_by_bytes);
2379 byte_idx++;
2380 }
2381 }
2382
2384 .modeOfOperation = mode_of_operation,
2385 .filePathLen = file_path_len,
2386 .filePath = (file_path_len == 0U) ? NULL : &r->recv_buf[4],
2387 .dataFormatIdentifier = data_format_identifier,
2388 .fileSizeUnCompressed = file_size_uncompressed,
2389 .fileSizeCompressed = file_size_compressed,
2390 .maxNumberOfBlockLength = UDS_TP_MTU,
2391 .filePosition = 0,
2392 };
2393
2394 UDSErr_t err = EmitEvent(srv, UDS_EVT_RequestFileTransfer, &args);
2395
2396 if (UDS_PositiveResponse != err) {
2397 return err;
2398 }
2399
2400 r->send_buf[0] = AsResponseSID(UDS_SID_REQUEST_FILE_TRANSFER);
2401 r->send_buf[1] = mode_of_operation;
2402
2403 if (mode_of_operation == UDS_MOOP_DELFILE) {
2404 r->send_len = 2;
2405 return UDS_OK;
2406 }
2407
2409 UDS_LOGW(__FILE__, "Clamping maxNumberOfBlockLength %hu to %hu",
2412 }
2413
2414 BeginTransfer(srv, args.fileSizeCompressed, args.maxNumberOfBlockLength);
2415
2416 // lengthFormatIdentifier: A_Data byte 3
2417 r->send_buf[2] = (uint8_t)sizeof(args.maxNumberOfBlockLength);
2418 r->send_len = 3;
2419
2420 // A_Data bytes 4 to 4+m-1: maxNumberOfBlockLength
2421 PackBE(&r->send_buf[r->send_len], args.maxNumberOfBlockLength,
2422 sizeof(args.maxNumberOfBlockLength));
2423 r->send_len += (size_t)sizeof(args.maxNumberOfBlockLength);
2424
2425 // daataFormatIdentifier: 0 if ReadDir
2426 r->send_buf[r->send_len] =
2427 (UDS_MOOP_RDDIR == mode_of_operation) ? 0x00U : args.dataFormatIdentifier;
2428 r->send_len += 1U;
2429
2430 if ((mode_of_operation == UDS_MOOP_ADDFILE) || (mode_of_operation == UDS_MOOP_DELFILE) ||
2431 (mode_of_operation == UDS_MOOP_REPLFILE) || (mode_of_operation == UDS_MOOP_RSFILE)) {
2432 // pass
2433 } else {
2434 // fileSizeOrDirInfoParameterLength
2435 PackBE(&r->send_buf[r->send_len], sizeof(args.fileSizeUnCompressed), 2);
2436 r->send_len += 2U;
2437
2438 // fileSizeUncompressedOrDirInfoLength
2439 PackBE(&r->send_buf[r->send_len], args.fileSizeUnCompressed,
2440 sizeof(args.fileSizeUnCompressed));
2441 r->send_len += sizeof(args.fileSizeUnCompressed);
2442
2443 if (mode_of_operation == UDS_MOOP_RDDIR) {
2444 // pass
2445 } else {
2446 // fileSizeCompressed
2447 PackBE(&r->send_buf[r->send_len], args.fileSizeCompressed,
2448 sizeof(args.fileSizeCompressed));
2449 r->send_len += sizeof(args.fileSizeCompressed);
2450 }
2451 }
2452
2453 if ((mode_of_operation == UDS_MOOP_ADDFILE) || (mode_of_operation == UDS_MOOP_DELFILE) ||
2454 (mode_of_operation == UDS_MOOP_REPLFILE) || (mode_of_operation == UDS_MOOP_RDFILE) ||
2455 (mode_of_operation == UDS_MOOP_RDDIR)) {
2456 // pass
2457 } else {
2458 // filePosition
2459 PackBE(&r->send_buf[r->send_len], args.filePosition, sizeof(args.filePosition));
2460 r->send_len += sizeof(args.filePosition);
2461 }
2462 return UDS_OK;
2463}
2464
2465static UDSErr_t Handle_0x3D_WriteMemoryByAddress(UDSServer_t *srv, UDSReq_t *r) {
2466 UDSErr_t ret = UDS_PositiveResponse;
2467 uintptr_t address = 0;
2468 size_t length = 0;
2469
2470 if (r->recv_len < UDS_0X3D_REQ_MIN_LEN) {
2471 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
2472 }
2473
2474 ret = decodeAddressAndLength(r, &r->recv_buf[1], &address, &length);
2475 if (UDS_PositiveResponse != ret) {
2476 return NegativeResponse(r, ret);
2477 }
2478
2479 uint8_t memorySizeLength = (r->recv_buf[1] & 0xF0U) >> 4U;
2480 uint8_t memoryAddressLength = r->recv_buf[1] & 0x0FU;
2481
2482 uint8_t dataOffset = 2U + memorySizeLength + memoryAddressLength;
2483
2484 if ((dataOffset + length) != r->recv_len) {
2485 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
2486 }
2487
2489 .memAddr = address,
2490 .memSize = length,
2491 .data = &r->recv_buf[dataOffset],
2492 };
2493
2494 ret = EmitEvent(srv, UDS_EVT_WriteMemByAddr, &args);
2495 if (UDS_PositiveResponse != ret) {
2496 return NegativeResponse(r, ret);
2497 }
2498
2499 r->send_buf[0] = AsResponseSID(UDS_SID_WRITE_MEMORY_BY_ADDRESS);
2500 // echo addressAndLengthFormatIdentifier, memoryAddress, and memorySize
2501 (void)memcpy(&r->send_buf[1], &r->recv_buf[1], 1U + memorySizeLength + memoryAddressLength);
2502 r->send_len = UDS_0X3D_RESP_BASE_LEN + (size_t)memorySizeLength + (size_t)memoryAddressLength;
2503 return UDS_PositiveResponse;
2504}
2505
2506static UDSErr_t Handle_0x3E_TesterPresent(UDSServer_t *srv, UDSReq_t *r) {
2507 if ((r->recv_len < UDS_0X3E_REQ_MIN_LEN) || (r->recv_len > UDS_0X3E_REQ_MAX_LEN)) {
2508 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
2509 }
2510 uint8_t zeroSubFunction = r->recv_buf[1];
2511
2512 switch (zeroSubFunction) {
2513 case 0x00:
2514 case 0x80:
2516 r->send_buf[0] = AsResponseSID(UDS_SID_TESTER_PRESENT);
2517 r->send_buf[1] = 0x00;
2518 r->send_len = UDS_0X3E_RESP_LEN;
2519 return UDS_PositiveResponse;
2520 default:
2521 return NegativeResponse(r, UDS_NRC_SubFunctionNotSupported);
2522 }
2523}
2524
2525static UDSErr_t Handle_0x85_ControlDTCSetting(UDSServer_t *srv, UDSReq_t *r) {
2526 (void)srv;
2527 if (r->recv_len < UDS_0X85_REQ_BASE_LEN) {
2528 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
2529 }
2530
2531 uint8_t type = r->recv_buf[1] & 0x7FU;
2532
2534 .type = type,
2535 .data = (r->recv_len > UDS_0X85_REQ_BASE_LEN) ? &r->recv_buf[UDS_0X85_REQ_BASE_LEN] : NULL,
2536 .len = (r->recv_len > UDS_0X85_REQ_BASE_LEN) ? (r->recv_len - UDS_0X85_REQ_BASE_LEN) : 0U,
2537 };
2538
2539 UDSErr_t ret = EmitEvent(srv, UDS_EVT_ControlDTCSetting, &args);
2540 if (UDS_PositiveResponse != ret) {
2541 return NegativeResponse(r, ret);
2542 }
2543
2544 r->send_buf[0] = AsResponseSID(UDS_SID_CONTROL_DTC_SETTING);
2545 r->send_buf[1] = type;
2546 r->send_len = UDS_0X85_RESP_LEN;
2547 return UDS_PositiveResponse;
2548}
2549
2550static UDSErr_t Handle_0x87_LinkControl(UDSServer_t *srv, UDSReq_t *r) {
2551 if (r->recv_len < UDS_0X85_REQ_BASE_LEN) {
2552 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
2553 }
2554
2555 uint8_t type = r->recv_buf[1] & 0x7FU;
2556
2557 if ((type == 0x03U) && ((r->recv_buf[1] & 0x80U) == 0U) &&
2558 (r->info.A_TA_Type == UDS_A_TA_TYPE_FUNCTIONAL)) {
2559 UDS_LOGW(__FILE__, "0x87 LinkControl: Transitioning mode without suppressing response!");
2560 }
2561
2562 r->send_buf[0] = AsResponseSID(UDS_SID_LINK_CONTROL);
2563 r->send_buf[1] = r->recv_buf[1]; /* do not use `type` because we want to preserve the suppress
2564 response bit */
2565 r->send_len = UDS_0X87_RESP_LEN;
2566
2567 UDSLinkCtrlArgs_t args = {
2568 .type = type,
2569 .len = (r->recv_len - UDS_0X87_REQ_BASE_LEN),
2570 .data = &r->recv_buf[UDS_0X87_REQ_BASE_LEN],
2571 };
2572
2573 UDSErr_t err = EmitEvent(srv, UDS_EVT_LinkControl, &args);
2574 if (err != UDS_PositiveResponse) {
2575 return NegativeResponse(r, err);
2576 }
2577
2578 return UDS_PositiveResponse;
2579}
2580
2581/// signature of internal service handlers
2583
2584/**
2585 * @brief Get the internal service handler matching the given SID.
2586 * @param sid
2587 * @return pointer to UDSService or NULL if no match
2588 */
2589static UDSService getServiceForSID(uint8_t sid) {
2590 switch (sid) {
2591 case UDS_SID_DIAGNOSTIC_SESSION_CONTROL:
2592 return &Handle_0x10_DiagnosticSessionControl;
2593 case UDS_SID_ECU_RESET:
2594 return &Handle_0x11_ECUReset;
2595 case UDS_SID_CLEAR_DIAGNOSTIC_INFORMATION:
2596 return &Handle_0x14_ClearDiagnosticInformation;
2597 case UDS_SID_READ_DTC_INFORMATION:
2598 return Handle_0x19_ReadDTCInformation;
2599 case UDS_SID_READ_DATA_BY_IDENTIFIER:
2600 return &Handle_0x22_ReadDataByIdentifier;
2601 case UDS_SID_READ_MEMORY_BY_ADDRESS:
2602 return &Handle_0x23_ReadMemoryByAddress;
2603 case UDS_SID_READ_SCALING_DATA_BY_IDENTIFIER:
2604 return NULL;
2605 case UDS_SID_SECURITY_ACCESS:
2606 return &Handle_0x27_SecurityAccess;
2607 case UDS_SID_COMMUNICATION_CONTROL:
2608 return &Handle_0x28_CommunicationControl;
2609 case UDS_SID_READ_PERIODIC_DATA_BY_IDENTIFIER:
2610 return NULL;
2611 case UDS_SID_DYNAMICALLY_DEFINE_DATA_IDENTIFIER:
2612 return &Handle_0x2C_DynamicDefineDataIdentifier;
2613 case UDS_SID_WRITE_DATA_BY_IDENTIFIER:
2614 return &Handle_0x2E_WriteDataByIdentifier;
2615 case UDS_SID_IO_CONTROL_BY_IDENTIFIER:
2616 return &Handle_0x2F_IOControlByIdentifier;
2617 case UDS_SID_ROUTINE_CONTROL:
2618 return &Handle_0x31_RoutineControl;
2619 case UDS_SID_REQUEST_DOWNLOAD:
2620 return &Handle_0x34_RequestDownload;
2621 case UDS_SID_REQUEST_UPLOAD:
2622 return &Handle_0x35_RequestUpload;
2623 case UDS_SID_TRANSFER_DATA:
2624 return &Handle_0x36_TransferData;
2625 case UDS_SID_REQUEST_TRANSFER_EXIT:
2626 return &Handle_0x37_RequestTransferExit;
2627 case UDS_SID_REQUEST_FILE_TRANSFER:
2628 return &Handle_0x38_RequestFileTransfer;
2629 case UDS_SID_WRITE_MEMORY_BY_ADDRESS:
2630 return &Handle_0x3D_WriteMemoryByAddress;
2631 case UDS_SID_TESTER_PRESENT:
2632 return &Handle_0x3E_TesterPresent;
2633 case UDS_SID_ACCESS_TIMING_PARAMETER:
2634 case UDS_SID_SECURED_DATA_TRANSMISSION:
2635 return NULL;
2636 case UDS_SID_CONTROL_DTC_SETTING:
2637 return &Handle_0x85_ControlDTCSetting;
2638 case UDS_SID_RESPONSE_ON_EVENT:
2639 return NULL;
2640 case UDS_SID_LINK_CONTROL:
2641 return &Handle_0x87_LinkControl;
2642 default:
2643 UDS_LOGI(__FILE__, "no handler for request SID %x", sid);
2644 return NULL;
2645 }
2646}
2647
2648/**
2649 * @brief Call the service if it exists, modifying the response if the spec calls for it.
2650 * @note see UDS-1 2013 7.5.5 Pseudo code example of server response behavior
2651 *
2652 * @param srv
2653 * @param addressingScheme
2654 */
2655static UDSErr_t evaluateServiceResponse(UDSServer_t *srv, UDSReq_t *r) {
2656 UDSErr_t response = UDS_PositiveResponse;
2657 bool suppressResponse = false;
2658 uint8_t sid = r->recv_buf[0];
2659 UDSService service = getServiceForSID(sid);
2660
2661 if (NULL == srv->fn) {
2662 return NegativeResponse(r, UDS_NRC_ServiceNotSupported);
2663 }
2664 UDS_ASSERT(srv->fn); // service handler functions will call srv->fn. it must be valid
2665
2666 switch (sid) {
2667 /* CASE Service_with_sub-function */
2668 /* test if service with sub-function is supported */
2669 case UDS_SID_DIAGNOSTIC_SESSION_CONTROL:
2670 case UDS_SID_ECU_RESET:
2671 case UDS_SID_SECURITY_ACCESS:
2672 case UDS_SID_COMMUNICATION_CONTROL:
2673 case UDS_SID_ROUTINE_CONTROL:
2674 case UDS_SID_TESTER_PRESENT:
2675 case UDS_SID_CONTROL_DTC_SETTING:
2676 case UDS_SID_LINK_CONTROL: {
2677 UDS_ASSERT(service);
2678 response = service(srv, r);
2679
2680 bool suppressPosRspMsgIndicationBit = (r->recv_buf[1] & 0x80U) != 0U;
2681
2682 /* test if positive response is required and if responseCode is positive 0x00 */
2683 if (suppressPosRspMsgIndicationBit && (response == UDS_PositiveResponse) &&
2684
2685 // TODO: *not yet a NRC 0x78 response sent*
2686 true) {
2687 suppressResponse = true;
2688 } else {
2689 suppressResponse = false;
2690 }
2691 break;
2692 }
2693
2694 /* CASE Service_without_sub-function */
2695 /* test if service without sub-function is supported */
2696 case UDS_SID_READ_DATA_BY_IDENTIFIER:
2697 case UDS_SID_READ_MEMORY_BY_ADDRESS:
2698 case UDS_SID_WRITE_DATA_BY_IDENTIFIER:
2699 case UDS_SID_REQUEST_DOWNLOAD:
2700 case UDS_SID_REQUEST_UPLOAD:
2701 case UDS_SID_TRANSFER_DATA:
2702 case UDS_SID_REQUEST_FILE_TRANSFER:
2703 case UDS_SID_REQUEST_TRANSFER_EXIT: {
2704 UDS_ASSERT(service);
2705 response = service(srv, r);
2706 break;
2707 }
2708
2709 /* CASE Service_optional */
2710 case UDS_SID_CLEAR_DIAGNOSTIC_INFORMATION:
2711 case UDS_SID_READ_DTC_INFORMATION:
2712 case UDS_SID_READ_SCALING_DATA_BY_IDENTIFIER:
2713 case UDS_SID_READ_PERIODIC_DATA_BY_IDENTIFIER:
2714 case UDS_SID_DYNAMICALLY_DEFINE_DATA_IDENTIFIER:
2715 case UDS_SID_IO_CONTROL_BY_IDENTIFIER:
2716 case UDS_SID_WRITE_MEMORY_BY_ADDRESS:
2717 case UDS_SID_ACCESS_TIMING_PARAMETER:
2718 case UDS_SID_SECURED_DATA_TRANSMISSION:
2719 case UDS_SID_RESPONSE_ON_EVENT:
2720 default: {
2721 if (service != NULL) {
2722 response = service(srv, r);
2723 } else {
2724 // this branch handles SIDs for which there is no registered handler.
2725 UDS_ASSERT(NULL == getServiceForSID(sid));
2726
2727 // The standard says that the response ID (RID) is SID-0x40.
2728 // Both SID and RID are uint8_t, therefore no SID can be
2729 // greater than 0xFF-0x40 = 0xBF
2730 if (sid > 0xBFU) {
2731 return NegativeResponse(r, UDS_NRC_ServiceNotSupported);
2732 }
2733
2734 UDSCustomArgs_t args = {
2735 .sid = sid,
2736 .optionRecord = &r->recv_buf[1],
2737 .len = (uint16_t)(r->recv_len - 1U),
2738 .copyResponse = safe_copy,
2739 };
2740
2741 r->send_buf[0] = AsResponseSID(sid);
2742 r->send_len = 1;
2743
2744 response = EmitEvent(srv, UDS_EVT_Custom, &args);
2745 if (UDS_PositiveResponse != response) {
2746 return NegativeResponse(r, response);
2747 }
2748 break;
2749 }
2750 }
2751 }
2752
2753 if ((UDS_A_TA_TYPE_FUNCTIONAL == r->info.A_TA_Type) &&
2754 ((UDS_NRC_ServiceNotSupported == response) ||
2755 (UDS_NRC_SubFunctionNotSupported == response) ||
2756 (UDS_NRC_ServiceNotSupportedInActiveSession == response) ||
2757 (UDS_NRC_SubFunctionNotSupportedInActiveSession == response) ||
2758 (UDS_NRC_RequestOutOfRange == response)) &&
2759
2760 // TODO: *not yet a NRC 0x78 response sent*
2761 true) {
2762 /* Suppress negative response message */
2763 suppressResponse = true;
2764 }
2765
2766 if (suppressResponse) {
2767 NoResponse(r);
2768 } else { /* send negative or positive response */
2769 }
2770 return response;
2771}
2772
2774 if (NULL == srv) {
2775 return UDS_ERR_INVALID_ARG;
2776 }
2777 (void)memset(srv, 0, sizeof(UDSServer_t));
2782 srv->p2_timer = UDSMillis() + srv->p2_ms;
2787 return UDS_OK;
2788}
2789
2791
2792 // UDS-1-2013 Figure 38: Session Timeout (S3)
2793 if ((UDS_LEV_DS_DS != srv->sessionType) &&
2794 UDSTimeAfter(UDSMillis(), srv->s3_session_timeout_timer)) {
2795 (void)EmitEvent(srv, UDS_EVT_SessionTimeout, NULL);
2797 srv->securityLevel = 0;
2798 }
2799
2800 if (srv->ecuResetScheduled && UDSTimeAfter(UDSMillis(), srv->ecuResetTimer)) {
2801 (void)EmitEvent(srv, UDS_EVT_DoScheduledReset, &srv->ecuResetScheduled);
2802 }
2803
2804 {
2805 UDSErr_t err = UDSTpPoll(srv->tp);
2806 if (UDS_OK != err) {
2807 (void)EmitEvent(srv, UDS_EVT_Err, &err);
2808 UDS_LOGE(__FILE__, "UDSTpPoll failed with %s", UDSErrToStr(err));
2809 }
2810 }
2811
2812 UDSReq_t *r = &srv->r;
2813
2814 if (srv->requestInProgress) {
2815 if (srv->RCRRP) {
2816 // responds only if
2817 // 1. changed (no longer RCRRP), or
2818 // 2. p2_timer has elapsed
2819 UDSErr_t response = evaluateServiceResponse(srv, r);
2820 if (UDS_NRC_RequestCorrectlyReceived_ResponsePending == response) {
2821 // it's the second time the service has responded with RCRRP
2822 srv->notReadyToReceive = true;
2823 } else {
2824 // No longer RCRRP'ing
2825 srv->RCRRP = false;
2826 srv->notReadyToReceive = false;
2827
2828 // Not a consecutive 0x78 response, use p2 instead of p2_star * 0.3
2829 srv->p2_timer = UDSMillis() + srv->p2_ms;
2830 }
2831 }
2832
2833 if (UDSTimeAfter(UDSMillis(), srv->p2_timer)) {
2834
2835 if (r->send_len > 0U) {
2836 UDSErr_t err = UDS_OK;
2837 err = UDSTpSend(srv->tp, r->send_buf, r->send_len, NULL);
2838 if (UDS_OK != err) {
2839 (void)EmitEvent(srv, UDS_EVT_Err, &err);
2840 UDS_LOGE(__FILE__, "UDSTpSend failed with %s", UDSErrToStr(err));
2841 }
2842 }
2843
2844 if (srv->RCRRP) {
2845 // ISO14229-2:2013 Table 4 footnote b
2846 // min time between consecutive 0x78 responses is 0.3 * p2*
2847 uint32_t wait_time = srv->p2_star_ms * 3U / 10U;
2848 srv->p2_timer = UDSMillis() + wait_time;
2849 } else {
2850 srv->p2_timer = UDSMillis() + srv->p2_ms;
2851 srv->requestInProgress = false;
2852 }
2853 }
2854
2855 } else {
2856 if (srv->notReadyToReceive) {
2857 return; // cannot respond to request right now
2858 }
2859 size_t tmp = 0;
2860 UDSErr_t err = UDSTpRecv(srv->tp, r->recv_buf, sizeof(r->recv_buf), &tmp, &r->info);
2861 if (UDS_OK != err) {
2862 UDS_LOGE(__FILE__, "UDSTpRecv failed with %s\n", UDSErrToStr(err));
2863 return;
2864 }
2865 r->recv_len = tmp;
2866
2867 if (r->recv_len > 0U) {
2868 UDSErr_t response = evaluateServiceResponse(srv, r);
2869 srv->requestInProgress = true;
2870 if (UDS_NRC_RequestCorrectlyReceived_ResponsePending == response) {
2871 srv->RCRRP = true;
2872 }
2873 }
2874 }
2875}
2876
2877
2878#ifdef UDS_LINES
2879#line 1 "src/tp.c"
2880#endif // #ifdef UDS_LINES
2881
2882
2883
2884UDSErr_t UDSTpSend(UDSTp_t *hdl, const uint8_t *buf, const size_t len, const UDSSDU_t *info) {
2885 UDS_ASSERT(hdl);
2886 UDS_ASSERT(hdl->send);
2887 UDS_ASSERT(buf);
2888 return hdl->send(hdl, buf, len, info);
2889}
2890
2891UDSErr_t UDSTpRecv(UDSTp_t *hdl, uint8_t *buf, const size_t bufsiz, size_t *recvlen,
2892 UDSSDU_t *info) {
2893 UDS_ASSERT(hdl);
2894 UDS_ASSERT(hdl->recv);
2895 UDS_ASSERT(recvlen);
2896 return hdl->recv(hdl, buf, bufsiz, recvlen, info);
2897}
2898
2900 UDS_ASSERT(hdl);
2901 UDS_ASSERT(hdl->poll);
2902 return hdl->poll(hdl);
2903}
2904
2905
2906#ifdef UDS_LINES
2907#line 1 "src/util.c"
2908#endif // #ifdef UDS_LINES
2909
2910
2911
2912
2913
2914
2915#ifdef UDS_CUSTOM_MILLIS
2916// the user is expected to provide a UDSMillis implementation
2917#else
2918uint32_t UDSMillis(void) {
2919#if UDS_SYS == UDS_SYS_UNIX
2920 struct timeval te;
2921 gettimeofday(&te, NULL);
2922 long long milliseconds = (te.tv_sec * 1000LL) + (te.tv_usec / 1000);
2923 return (uint32_t)milliseconds;
2924#elif UDS_SYS == UDS_SYS_WINDOWS
2925 struct timespec ts;
2926 timespec_get(&ts, TIME_UTC);
2927 long long milliseconds = ts.tv_sec * 1000LL + ts.tv_nsec / 1000000;
2928 return (uint32_t)milliseconds;
2929#elif UDS_SYS == UDS_SYS_ARDUINO
2930 return millis();
2931#elif UDS_SYS == UDS_SYS_ESP32
2932 return esp_timer_get_time() / 1000;
2933#elif UDS_SYS == UDS_SYS_ZEPHYR
2934 return k_uptime_get_32();
2935#else
2936#error "UDSMillis not implemented for this UDS_SYS"
2937#endif
2938}
2939#endif // defined(UDS_CUSTOM_MILLIS)
2940
2941const char *UDSErrToStr(UDSErr_t err) {
2942 switch (err) {
2943 case UDS_OK:
2944 return "UDS_OK";
2945 case UDS_FAIL:
2946 return "UDS_FAIL";
2947 case UDS_NRC_GeneralReject:
2948 return "UDS_NRC_GeneralReject";
2949 case UDS_NRC_ServiceNotSupported:
2950 return "UDS_NRC_ServiceNotSupported";
2951 case UDS_NRC_SubFunctionNotSupported:
2952 return "UDS_NRC_SubFunctionNotSupported";
2953 case UDS_NRC_IncorrectMessageLengthOrInvalidFormat:
2954 return "UDS_NRC_IncorrectMessageLengthOrInvalidFormat";
2955 case UDS_NRC_ResponseTooLong:
2956 return "UDS_NRC_ResponseTooLong";
2957 case UDS_NRC_BusyRepeatRequest:
2958 return "UDS_NRC_BusyRepeatRequest";
2959 case UDS_NRC_ConditionsNotCorrect:
2960 return "UDS_NRC_ConditionsNotCorrect";
2961 case UDS_NRC_RequestSequenceError:
2962 return "UDS_NRC_RequestSequenceError";
2963 case UDS_NRC_NoResponseFromSubnetComponent:
2964 return "UDS_NRC_NoResponseFromSubnetComponent";
2965 case UDS_NRC_FailurePreventsExecutionOfRequestedAction:
2966 return "UDS_NRC_FailurePreventsExecutionOfRequestedAction";
2967 case UDS_NRC_RequestOutOfRange:
2968 return "UDS_NRC_RequestOutOfRange";
2969 case UDS_NRC_SecurityAccessDenied:
2970 return "UDS_NRC_SecurityAccessDenied";
2971 case UDS_NRC_AuthenticationRequired:
2972 return "UDS_NRC_AuthenticationRequired";
2973 case UDS_NRC_InvalidKey:
2974 return "UDS_NRC_InvalidKey";
2975 case UDS_NRC_ExceedNumberOfAttempts:
2976 return "UDS_NRC_ExceedNumberOfAttempts";
2977 case UDS_NRC_RequiredTimeDelayNotExpired:
2978 return "UDS_NRC_RequiredTimeDelayNotExpired";
2979 case UDS_NRC_SecureDataTransmissionRequired:
2980 return "UDS_NRC_SecureDataTransmissionRequired";
2981 case UDS_NRC_SecureDataTransmissionNotAllowed:
2982 return "UDS_NRC_SecureDataTransmissionNotAllowed";
2983 case UDS_NRC_SecureDataVerificationFailed:
2984 return "UDS_NRC_SecureDataVerificationFailed";
2985 case UDS_NRC_CertficateVerificationFailedInvalidTimePeriod:
2986 return "UDS_NRC_CertficateVerificationFailedInvalidTimePeriod";
2987 case UDS_NRC_CertficateVerificationFailedInvalidSignature:
2988 return "UDS_NRC_CertficateVerificationFailedInvalidSignature";
2989 case UDS_NRC_CertficateVerificationFailedInvalidChainOfTrust:
2990 return "UDS_NRC_CertficateVerificationFailedInvalidChainOfTrust";
2991 case UDS_NRC_CertficateVerificationFailedInvalidType:
2992 return "UDS_NRC_CertficateVerificationFailedInvalidType";
2993 case UDS_NRC_CertficateVerificationFailedInvalidFormat:
2994 return "UDS_NRC_CertficateVerificationFailedInvalidFormat";
2995 case UDS_NRC_CertficateVerificationFailedInvalidContent:
2996 return "UDS_NRC_CertficateVerificationFailedInvalidContent";
2997 case UDS_NRC_CertficateVerificationFailedInvalidScope:
2998 return "UDS_NRC_CertficateVerificationFailedInvalidScope";
2999 case UDS_NRC_CertficateVerificationFailedInvalidCertificate:
3000 return "UDS_NRC_CertficateVerificationFailedInvalidCertificate";
3001 case UDS_NRC_OwnershipVerificationFailed:
3002 return "UDS_NRC_OwnershipVerificationFailed";
3003 case UDS_NRC_ChallengeCalculationFailed:
3004 return "UDS_NRC_ChallengeCalculationFailed";
3005 case UDS_NRC_SettingAccessRightsFailed:
3006 return "UDS_NRC_SettingAccessRightsFailed";
3007 case UDS_NRC_SessionKeyCreationOrDerivationFailed:
3008 return "UDS_NRC_SessionKeyCreationOrDerivationFailed";
3009 case UDS_NRC_ConfigurationDataUsageFailed:
3010 return "UDS_NRC_ConfigurationDataUsageFailed";
3011 case UDS_NRC_DeAuthenticationFailed:
3012 return "UDS_NRC_DeAuthenticationFailed";
3013 case UDS_NRC_UploadDownloadNotAccepted:
3014 return "UDS_NRC_UploadDownloadNotAccepted";
3015 case UDS_NRC_TransferDataSuspended:
3016 return "UDS_NRC_TransferDataSuspended";
3017 case UDS_NRC_GeneralProgrammingFailure:
3018 return "UDS_NRC_GeneralProgrammingFailure";
3019 case UDS_NRC_WrongBlockSequenceCounter:
3020 return "UDS_NRC_WrongBlockSequenceCounter";
3021 case UDS_NRC_RequestCorrectlyReceived_ResponsePending:
3022 return "UDS_NRC_RequestCorrectlyReceived_ResponsePending";
3023 case UDS_NRC_SubFunctionNotSupportedInActiveSession:
3024 return "UDS_NRC_SubFunctionNotSupportedInActiveSession";
3025 case UDS_NRC_ServiceNotSupportedInActiveSession:
3026 return "UDS_NRC_ServiceNotSupportedInActiveSession";
3027 case UDS_NRC_RpmTooHigh:
3028 return "UDS_NRC_RpmTooHigh";
3029 case UDS_NRC_RpmTooLow:
3030 return "UDS_NRC_RpmTooLow";
3031 case UDS_NRC_EngineIsRunning:
3032 return "UDS_NRC_EngineIsRunning";
3033 case UDS_NRC_EngineIsNotRunning:
3034 return "UDS_NRC_EngineIsNotRunning";
3035 case UDS_NRC_EngineRunTimeTooLow:
3036 return "UDS_NRC_EngineRunTimeTooLow";
3037 case UDS_NRC_TemperatureTooHigh:
3038 return "UDS_NRC_TemperatureTooHigh";
3039 case UDS_NRC_TemperatureTooLow:
3040 return "UDS_NRC_TemperatureTooLow";
3041 case UDS_NRC_VehicleSpeedTooHigh:
3042 return "UDS_NRC_VehicleSpeedTooHigh";
3043 case UDS_NRC_VehicleSpeedTooLow:
3044 return "UDS_NRC_VehicleSpeedTooLow";
3045 case UDS_NRC_ThrottlePedalTooHigh:
3046 return "UDS_NRC_ThrottlePedalTooHigh";
3047 case UDS_NRC_ThrottlePedalTooLow:
3048 return "UDS_NRC_ThrottlePedalTooLow";
3049 case UDS_NRC_TransmissionRangeNotInNeutral:
3050 return "UDS_NRC_TransmissionRangeNotInNeutral";
3051 case UDS_NRC_TransmissionRangeNotInGear:
3052 return "UDS_NRC_TransmissionRangeNotInGear";
3053 case UDS_NRC_BrakeSwitchNotClosed:
3054 return "UDS_NRC_BrakeSwitchNotClosed";
3055 case UDS_NRC_ShifterLeverNotInPark:
3056 return "UDS_NRC_ShifterLeverNotInPark";
3057 case UDS_NRC_TorqueConverterClutchLocked:
3058 return "UDS_NRC_TorqueConverterClutchLocked";
3059 case UDS_NRC_VoltageTooHigh:
3060 return "UDS_NRC_VoltageTooHigh";
3061 case UDS_NRC_VoltageTooLow:
3062 return "UDS_NRC_VoltageTooLow";
3063 case UDS_NRC_ResourceTemporarilyNotAvailable:
3064 return "UDS_NRC_ResourceTemporarilyNotAvailable";
3065 case UDS_ERR_TIMEOUT:
3066 return "UDS_ERR_TIMEOUT";
3067 case UDS_ERR_DID_MISMATCH:
3068 return "UDS_ERR_DID_MISMATCH";
3069 case UDS_ERR_SID_MISMATCH:
3070 return "UDS_ERR_SID_MISMATCH";
3071 case UDS_ERR_SUBFUNCTION_MISMATCH:
3072 return "UDS_ERR_SUBFUNCTION_MISMATCH";
3073 case UDS_ERR_TPORT:
3074 return "UDS_ERR_TPORT";
3075 case UDS_ERR_RESP_TOO_SHORT:
3076 return "UDS_ERR_RESP_TOO_SHORT";
3077 case UDS_ERR_BUFSIZ:
3078 return "UDS_ERR_BUFSIZ";
3079 case UDS_ERR_INVALID_ARG:
3080 return "UDS_ERR_INVALID_ARG";
3081 case UDS_ERR_BUSY:
3082 return "UDS_ERR_BUSY";
3083 case UDS_ERR_MISUSE:
3084 return "UDS_ERR_MISUSE";
3085 default:
3086 return "unknown";
3087 }
3088}
3089
3090const char *UDSEventToStr(UDSEvent_t evt) {
3091
3092 switch (evt) {
3093 case UDS_EVT_Custom:
3094 return "UDS_EVT_Custom";
3095 case UDS_EVT_Err:
3096 return "UDS_EVT_Err";
3098 return "UDS_EVT_DiagSessCtrl";
3099 case UDS_EVT_EcuReset:
3100 return "UDS_EVT_EcuReset";
3102 return "UDS_EVT_ReadDataByIdent";
3104 return "UDS_EVT_ReadMemByAddr";
3105 case UDS_EVT_CommCtrl:
3106 return "UDS_EVT_CommCtrl";
3108 return "UDS_EVT_SecAccessRequestSeed";
3110 return "UDS_EVT_SecAccessValidateKey";
3112 return "UDS_EVT_WriteDataByIdent";
3114 return "UDS_EVT_RoutineCtrl";
3116 return "UDS_EVT_RequestDownload";
3118 return "UDS_EVT_RequestUpload";
3120 return "UDS_EVT_TransferData";
3122 return "UDS_EVT_RequestTransferExit";
3124 return "UDS_EVT_SessionTimeout";
3126 return "UDS_EVT_DoScheduledReset";
3128 return "UDS_EVT_RequestFileTransfer";
3129 case UDS_EVT_Poll:
3130 return "UDS_EVT_Poll";
3132 return "UDS_EVT_SendComplete";
3134 return "UDS_EVT_ResponseReceived";
3135 case UDS_EVT_Idle:
3136 return "UDS_EVT_Idle";
3137 case UDS_EVT_MAX:
3138 return "UDS_EVT_MAX";
3139 default:
3140 return "unknown";
3141 }
3142}
3143
3144
3145#ifdef UDS_LINES
3146#line 1 "src/log.c"
3147#endif // #ifdef UDS_LINES
3148
3149
3150
3151#if UDS_LOG_LEVEL > UDS_LOG_NONE
3152void UDS_LogWrite(UDS_LogLevel_t level, const char *tag, const char *format, ...) {
3153 va_list list;
3154 (void)level;
3155 (void)tag;
3156 va_start(list, format);
3157 (void)vprintf(format, list);
3158 va_end(list);
3159}
3160
3161void UDS_LogSDUInternal(UDS_LogLevel_t level, const char *tag, const uint8_t *buffer, size_t buflen,
3162 const UDSSDU_t *info) {
3163 (void)info;
3164 for (size_t i = 0; i < buflen; i++) {
3165 UDS_LogWrite(level, tag, "%02x ", buffer[i]);
3166 }
3167 UDS_LogWrite(level, tag, "\n");
3168}
3169#endif // UDS_LOG_LEVEL > UDS_LOG_NONE
3170
3171#ifdef UDS_TP_ISOTP_C
3172#ifdef UDS_LINES
3173#line 1 "src/tp/isotp_c.c"
3174#endif // #ifdef UDS_LINES
3175
3176
3177
3178
3179
3180
3181
3182UDSErr_t UDSTpISOTpCPoll(UDSTp_t *hdl) {
3183 UDSTpISOTpC_t *impl = (UDSTpISOTpC_t *)hdl; // cppcheck-suppress [misra-c2012-11.3]
3184 isotp_poll(&impl->phys_link);
3185 isotp_poll(&impl->func_link);
3186 if (ISOTP_SEND_STATUS_INPROGRESS == impl->phys_link.send_status) {
3187 hdl->status.is_sending = 1;
3188 } else {
3189 hdl->status.is_sending = 0;
3190 }
3191
3192 if (ISOTP_SEND_STATUS_ERROR == impl->phys_link.send_status) {
3193 return UDS_ERR_TPORT;
3194 } else {
3195 return UDS_OK;
3196 }
3197}
3198
3199static UDSErr_t tp_send(UDSTp_t *hdl, const uint8_t *buf, size_t len, const UDSSDU_t *info) {
3200 UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl; // cppcheck-suppress [misra-c2012-11.3]
3201 IsoTpLink *link = NULL;
3202 const UDS_A_TA_Type_t ta_type = info ? info->A_TA_Type : UDS_A_TA_TYPE_PHYSICAL;
3203
3204 if (len > UINT32_MAX) {
3205 return UDS_FAIL;
3206 }
3207
3208 switch (ta_type) {
3209 case UDS_A_TA_TYPE_PHYSICAL:
3210 link = &tp->phys_link;
3211 break;
3212 case UDS_A_TA_TYPE_FUNCTIONAL:
3213 link = &tp->func_link;
3214 if (len > 7U) {
3215 UDS_LOGE(__FILE__, "Cannot send more than 7 bytes via functional addressing");
3216 return UDS_ERR_MISUSE;
3217 }
3218 break;
3219 default:
3220 UDS_LOGE(__FILE__, "unknown UDS_A_TA_TYPE");
3221 return UDS_ERR_MISUSE;
3222 }
3223
3224 int ret = isotp_send(link, buf, (uint32_t)len);
3225 switch (ret) {
3226 case ISOTP_RET_OK: {
3227 return UDS_OK;
3228 }
3229 case ISOTP_RET_INPROGRESS:
3230 case ISOTP_RET_OVERFLOW:
3231 default:
3232 return UDS_ERR_TPORT;
3233 }
3234}
3235
3236static inline UDSErr_t
3237safe_api_shim_isotp_receive(IsoTpLink *link, uint8_t *payload,
3238 const size_t payload_size, // size of payload buffer
3239 size_t *out_size, int *isotp_ret) {
3240 uint32_t u32out_size = 0;
3241
3242 if (payload_size > UINT32_MAX) { // max value of isotp_receive(payload_size)
3243 return UDS_FAIL;
3244 }
3245
3246 *isotp_ret = isotp_receive(link, payload, (uint32_t)payload_size, &u32out_size);
3247
3248#if UINT32_MAX > SIZE_MAX
3249 if (u32out_size > SIZE_MAX) {
3250 return UDS_FAIL;
3251 }
3252#endif
3253
3254 *out_size = u32out_size;
3255 return UDS_OK;
3256}
3257
3258static UDSErr_t tp_recv(UDSTp_t *hdl, uint8_t *buf, size_t bufsiz, size_t *recvlen,
3259 UDSSDU_t *info) {
3260 UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl; // cppcheck-suppress [misra-c2012-11.3]
3261 int ret = 0;
3262 UDSErr_t err = UDS_OK;
3263
3264 err = safe_api_shim_isotp_receive(&tp->phys_link, buf, bufsiz, recvlen, &ret);
3265 if (UDS_OK != err) {
3266 return err;
3267 }
3268 if (ISOTP_RET_OK == ret) {
3269 UDS_LOGI(__FILE__, "phys link received %zd bytes", *recvlen);
3270 if (NULL != info) {
3271 info->A_TA = tp->phys_sa;
3272 info->A_SA = tp->phys_ta;
3273 info->A_TA_Type = UDS_A_TA_TYPE_PHYSICAL;
3274 }
3275 } else if (ISOTP_RET_NO_DATA == ret) {
3276 err = safe_api_shim_isotp_receive(&tp->func_link, buf, bufsiz, recvlen, &ret);
3277 if (UDS_OK != err) {
3278 return err;
3279 }
3280 if (ISOTP_RET_OK == ret) {
3281 UDS_LOGI(__FILE__, "func link received %zd bytes", *recvlen);
3282 if (NULL != info) {
3283 info->A_TA = tp->func_sa;
3284 info->A_SA = tp->func_ta;
3285 info->A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL;
3286 }
3287 } else if (ISOTP_RET_NO_DATA == ret) {
3288 return 0;
3289 } else {
3290 UDS_LOGE(__FILE__, "unhandled return code from func link %d\n", ret);
3291 }
3292 } else {
3293 UDS_LOGE(__FILE__, "unhandled return code from phys link %d\n", ret);
3294 }
3295 return 0;
3296}
3297
3298UDSErr_t UDSTpISOTpCInit(UDSTpISOTpC_t *tp, uint32_t sa, uint32_t ta, uint32_t sa_func,
3299 uint32_t ta_func) {
3300 if (tp == NULL) {
3301 return UDS_ERR_INVALID_ARG;
3302 }
3303 tp->hdl.poll = UDSTpISOTpCPoll;
3304 tp->hdl.send = tp_send;
3305 tp->hdl.recv = tp_recv;
3306 tp->phys_sa = sa;
3307 tp->phys_ta = ta;
3308 tp->func_sa = sa_func;
3309 tp->func_ta = ta_func;
3310
3311 isotp_init_link(&tp->phys_link, tp->phys_ta, tp->send_buf, sizeof(tp->send_buf), tp->recv_buf,
3312 sizeof(tp->recv_buf));
3313 isotp_init_link(&tp->func_link, tp->func_ta, tp->func_send_buf, sizeof(tp->func_send_buf),
3314 tp->func_recv_buf, sizeof(tp->func_recv_buf));
3315 return UDS_OK;
3316}
3317
3318UDSErr_t UDSServerTpISOTpCInit(UDSTpISOTpC_t *tp, uint32_t source_addr, uint32_t target_addr,
3319 uint32_t source_addr_func) {
3320 return UDSTpISOTpCInit(tp, source_addr, target_addr, source_addr_func, UDS_TP_NOOP_ADDR);
3321}
3322
3323UDSErr_t UDSClientTpISOTpCInit(UDSTpISOTpC_t *tp, uint32_t source_addr, uint32_t target_addr,
3324 uint32_t target_addr_func) {
3325 return UDSTpISOTpCInit(tp, source_addr, target_addr, UDS_TP_NOOP_ADDR, target_addr_func);
3326}
3327
3328#endif
3329
3330#ifdef UDS_TP_ISOTP_C_SOCKETCAN
3331#ifdef UDS_LINES
3332#line 1 "src/tp/isotp_c_socketcan.c"
3333#endif // #ifdef UDS_LINES
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343static int SetupSocketCAN(const char *ifname) {
3344 struct sockaddr_can addr = {0};
3345 struct ifreq ifr = {0};
3346 int sockfd = socket(PF_CAN, SOCK_RAW | SOCK_NONBLOCK, CAN_RAW);
3347
3348 if (sockfd < 0) {
3349 perror("socket");
3350 return sockfd;
3351 }
3352
3353 (void)memset(&ifr, 0, sizeof(ifr));
3354 if (snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", ifname) >= (int)sizeof(ifr.ifr_name)) {
3355 UDS_LOGE(__FILE__, "Interface name too long");
3356 if (close(sockfd) < 0) {
3357 perror("close");
3358 }
3359 return -1;
3360 }
3361 if (ioctl(sockfd, SIOCGIFINDEX, &ifr) < 0) {
3362 perror("ioctl");
3363 }
3364 (void)memset(&addr, 0, sizeof(addr));
3365 addr.can_family = AF_CAN;
3366 addr.can_ifindex = ifr.ifr_ifindex;
3367 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
3368 perror("bind");
3369 }
3370 return sockfd;
3371}
3372
3373uint32_t isotp_user_get_us(void) { return UDSMillis() * 1000U; }
3374
3375__attribute__((format(printf, 1, 2))) void isotp_user_debug(const char *message, ...) {
3376 va_list args;
3377 va_start(args, message);
3378 (void)vprintf(message, args);
3379 va_end(args);
3380}
3381
3382#ifndef ISO_TP_USER_SEND_CAN_ARG
3383#error "ISO_TP_USER_SEND_CAN_ARG must be defined"
3384#endif
3385int isotp_user_send_can(const uint32_t arbitration_id, const uint8_t *data, const uint8_t size,
3386 void *user_data) {
3387 (void)fflush(stdout);
3388 UDS_ASSERT(user_data);
3389 int sockfd = 0;
3390 (void)memcpy(&sockfd, user_data, sizeof(sockfd));
3391 struct can_frame frame = {0};
3392 frame.can_id = arbitration_id;
3393 frame.can_dlc = size;
3394 (void)memmove(frame.data, data, size);
3395 ssize_t ret = write(sockfd, &frame, sizeof(struct can_frame));
3396 if (ret < 0) {
3397 perror("Write err");
3398 return ISOTP_RET_ERROR;
3399 }
3400 return ISOTP_RET_OK;
3401}
3402
3403static bool GetNextFrame(int fd, struct can_frame *frame) {
3404 UDS_ASSERT(frame);
3405 ssize_t nbytes = read(fd, frame, sizeof(struct can_frame));
3406 if (nbytes < 0) {
3407 if ((EAGAIN == errno) || (EWOULDBLOCK == errno)) {
3408 return false;
3409 } else {
3410 perror("read");
3411 return false;
3412 }
3413 } else if (nbytes == 0) {
3414 return false;
3415 } else {
3416 return true;
3417 }
3418}
3419
3420static void SocketCANRecv(UDSTpISOTpCSocketCAN_t *tp) {
3421 UDS_ASSERT(tp);
3422 struct can_frame frame = {0};
3423
3424 while (GetNextFrame(tp->fd, &frame)) {
3425 if (frame.can_id == tp->hdl2.phys_sa) {
3426 isotp_on_can_message(&tp->hdl2.phys_link, frame.data, frame.can_dlc);
3427 } else if (frame.can_id == tp->hdl2.func_sa) {
3428 isotp_on_can_message(&tp->hdl2.func_link, frame.data, frame.can_dlc);
3429 if (ISOTP_RECEIVE_STATUS_IDLE != tp->hdl2.func_link.receive_status) {
3430 UDS_LOGI(__FILE__,
3431 "func frame received but cannot process because link is not idle");
3432 break;
3433 }
3434 // TODO: reject if it's longer than a single frame
3435 isotp_on_can_message(&tp->hdl2.func_link, frame.data, frame.can_dlc);
3436 } else {
3437 UDS_LOGD(__FILE__, "received frame 0x%x not matching phys or func addresses",
3438 frame.can_id);
3439 }
3440 }
3441}
3442
3443static UDSErr_t isotp_c_socketcan_poll(UDSTp_t *hdl) {
3445 (UDSTpISOTpCSocketCAN_t *)hdl; // cppcheck-suppress [misra-c2012-11.3]
3446 SocketCANRecv(impl);
3447 return UDSTpISOTpCPoll((UDSTp_t *)&(impl->hdl2)); // cppcheck-suppress [misra-c2012-11.3]
3448}
3449
3450static UDSErr_t UDSTpISOTpCSocketCANInit(UDSTpISOTpCSocketCAN_t *tp, const char *ifname,
3451 uint32_t source_addr, uint32_t target_addr,
3452 uint32_t source_addr_func, uint32_t target_addr_func) {
3453 UDSErr_t err = UDS_OK;
3454
3455 err = UDSTpISOTpCInit(&tp->hdl2, source_addr, target_addr, source_addr_func, target_addr_func);
3456 if (UDS_OK != err) {
3457 return err;
3458 }
3459 UDSTp_t *hdl = (UDSTp_t *)tp; // cppcheck-suppress [misra-c2012-11.3]
3460 hdl->poll = isotp_c_socketcan_poll;
3461
3462 tp->fd = SetupSocketCAN(ifname);
3463 tp->hdl2.phys_link.user_send_can_arg = &(tp->fd);
3464 tp->hdl2.func_link.user_send_can_arg = &(tp->fd);
3465
3466 return UDS_OK;
3467}
3468
3470 uint32_t source_addr, uint32_t target_addr,
3471 uint32_t source_addr_func) {
3472 return UDSTpISOTpCSocketCANInit(tp, ifname, source_addr, target_addr, source_addr_func,
3474}
3475
3477 uint32_t source_addr, uint32_t target_addr,
3478 uint32_t target_addr_func) {
3479 return UDSTpISOTpCSocketCANInit(tp, ifname, source_addr, target_addr, UDS_TP_NOOP_ADDR,
3480 target_addr_func);
3481}
3482
3484 UDS_ASSERT(tp);
3485 if (close(tp->fd) < 0) {
3486 perror("close");
3487 }
3488 tp->fd = -1;
3489}
3490
3491#endif
3492
3493#ifdef UDS_TP_ISOTP_SOCK
3494#ifdef UDS_LINES
3495#line 1 "src/tp/isotp_sock.c"
3496#endif // #ifdef UDS_LINES
3497
3498
3499
3500
3501
3502
3503static bool revents_has(short revents, short flag) {
3504 return (bool)(((unsigned int)revents & (unsigned int)flag) != 0U);
3505}
3506
3507static UDSErr_t isotp_sock_tp_poll(UDSTp_t *hdl) {
3508 const UDSTpIsoTpSock_t *impl = (UDSTpIsoTpSock_t *)hdl; // cppcheck-suppress [misra-c2012-11.3]
3509 UDSErr_t err = UDS_OK;
3510 int ret = 0;
3511 const int fds[2] = {impl->phys_fd, impl->func_fd};
3512 struct pollfd pfds[2] = {0};
3513 pfds[0].fd = impl->phys_fd;
3514 pfds[0].events = POLLERR | POLLOUT;
3515 pfds[0].revents = 0;
3516
3517 pfds[1].fd = impl->func_fd;
3518 pfds[1].events = POLLERR | POLLOUT;
3519 pfds[1].revents = 0;
3520
3521 ret = poll(pfds, 2, 1);
3522 if (ret < 0) {
3523 UDS_LOGE(__FILE__, "poll failed: %d", ret);
3524 err = UDS_ERR_TPORT;
3525 } else if (ret == 0) {
3526 ; // timeout, no events
3527 } else {
3528 // poll() returned with events
3529 for (int i = 0; i < 2; i++) {
3530 struct pollfd pfd = pfds[i];
3531
3532 // Check for errors
3533 if (revents_has(pfd.revents, POLLERR)) {
3534 int pending_err = 0;
3535 socklen_t len = sizeof(pending_err);
3536 if (0 == getsockopt(fds[i], SOL_SOCKET, SO_ERROR, &pending_err, &len) &&
3537 pending_err) {
3538 if (ECOMM == pending_err) {
3539 UDS_LOGE(__FILE__, "ECOMM: Communication error on send");
3540 err = UDS_ERR_TPORT;
3541 } else {
3542 UDS_LOGE(__FILE__, "Asynchronous socket error: %s (%d)",
3543 strerror(pending_err), pending_err);
3544 }
3545 } else {
3546 UDS_LOGE(__FILE__, "POLLERR was set, but no error returned via SO_ERROR?");
3547 }
3548 }
3549
3550 // Check if send is in progress on physical socket
3551 // Only check the physical socket (not functional) since that's what sends multi-frame
3552 if ((fds[i] == impl->phys_fd) && (pfd.revents != 0)) {
3553 // When POLLOUT is NOT set but other events are present, the socket cannot accept
3554 // writes because a multi-frame transmission is in progress.
3555 // See: https://lore.kernel.org/all/20230331125511.372783-1-michal.sojka@cvut.cz/
3556 // The kernel ISO-TP driver suppresses POLLOUT when tx.state != ISOTP_IDLE
3557 if (!revents_has(pfd.revents, POLLOUT)) {
3558 hdl->status.is_sending = 1;
3559 } else {
3560 hdl->status.is_sending = 0;
3561 }
3562 }
3563 }
3564 }
3565 return err;
3566}
3567
3568static UDSErr_t tp_recv_once(int fd, uint8_t *buf, const size_t bufsiz, size_t *recvlen) {
3569 UDSErr_t err = UDS_OK;
3570 ssize_t ret = read(fd, buf, bufsiz);
3571 if (ret < 0) {
3572 if ((EAGAIN == errno) || (EWOULDBLOCK == errno)) {
3573 ; // temporarily unavailable -- not an error
3574 } else {
3575 UDS_LOGE(__FILE__, "read failed: %zd with errno: %d", ret, errno);
3576 err = UDS_FAIL;
3577 }
3578 }
3579
3580 *recvlen = (ret < 0) ? 0U : (size_t)ret;
3581 return err;
3582}
3583
3584static UDSErr_t isotp_sock_tp_recv(UDSTp_t *hdl, uint8_t *buf, const size_t bufsiz, size_t *recvlen,
3585 UDSSDU_t *info) {
3586 UDSTpIsoTpSock_t *impl = (UDSTpIsoTpSock_t *)hdl; // cppcheck-suppress [misra-c2012-11.3]
3587 UDSErr_t err = 0;
3588 UDSSDU_t *msg = &impl->recv_info;
3589
3590 err = tp_recv_once(impl->phys_fd, buf, bufsiz, recvlen);
3591 if (UDS_OK != err) {
3592 return err;
3593 }
3594 if (*recvlen > 0) {
3595 msg->A_TA = impl->phys_sa;
3596 msg->A_SA = impl->phys_ta;
3597 msg->A_TA_Type = UDS_A_TA_TYPE_PHYSICAL;
3598 } else {
3599 err = tp_recv_once(impl->func_fd, buf, bufsiz, recvlen);
3600 if (UDS_OK != err) {
3601 return err;
3602 }
3603 if (*recvlen > 0) {
3604 msg->A_TA = impl->func_sa;
3605 msg->A_SA = impl->func_ta;
3606 msg->A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL;
3607 }
3608 }
3609
3610 if (*recvlen > 0) {
3611 if (info != NULL) {
3612 *info = *msg;
3613 }
3614
3615 UDS_LOGD(__FILE__, "'%s' received %zd bytes from 0x%03x (%s), ", impl->tag, *recvlen,
3616 msg->A_TA, (msg->A_TA_Type == UDS_A_TA_TYPE_PHYSICAL) ? "phys" : "func");
3617 UDS_LOG_SDU(__FILE__, impl->recv_buf, *recvlen, msg);
3618 }
3619 return UDS_OK;
3620}
3621
3622static UDSErr_t isotp_sock_tp_send(UDSTp_t *hdl, const uint8_t *buf, const size_t len,
3623 const UDSSDU_t *info) {
3624 UDSTpIsoTpSock_t *impl = (UDSTpIsoTpSock_t *)hdl; // cppcheck-suppress [misra-c2012-11.3]
3625 ssize_t ret = -1;
3626 int fd = -1;
3627 const UDS_A_TA_Type_t ta_type = info ? info->A_TA_Type : UDS_A_TA_TYPE_PHYSICAL;
3628
3629 switch (ta_type) {
3630 case UDS_A_TA_TYPE_PHYSICAL:
3631 fd = impl->phys_fd;
3632 break;
3633 case UDS_A_TA_TYPE_FUNCTIONAL: {
3634 if (len > 7U) {
3635 UDS_LOGE(__FILE__, "UDSTpIsoTpSock: functional request too large");
3636 return UDS_ERR_MISUSE;
3637 }
3638 fd = impl->func_fd;
3639 } break;
3640 default:
3641 UDS_LOGE(__FILE__, "unknown UDS_A_TA_TYPE");
3642 return UDS_ERR_MISUSE;
3643 }
3644
3645 UDS_ASSERT(fd >= 0);
3646 ret = write(fd, buf, len);
3647 if (ret < 0) {
3648 perror("write");
3649 return UDS_FAIL;
3650 }
3651
3652 uint32_t ta = (ta_type == UDS_A_TA_TYPE_PHYSICAL) ? impl->phys_ta : impl->func_ta;
3653 UDS_LOGD(__FILE__, "'%s' sends %zu bytes to 0x%03x (%s)", impl->tag, len, ta,
3654 (ta_type == UDS_A_TA_TYPE_PHYSICAL) ? "phys" : "func");
3655 UDS_LOG_SDU(__FILE__, buf, len, info);
3656 return UDS_OK;
3657}
3658
3659static int LinuxSockBind(const char *if_name, uint32_t rxid, uint32_t txid, bool functional) {
3660 int fd = socket(AF_CAN, SOCK_DGRAM | SOCK_NONBLOCK, CAN_ISOTP);
3661 if (fd < 0) {
3662 perror("Socket");
3663 return -1;
3664 }
3665
3666 struct can_isotp_fc_options fcopts = {
3667 .bs = 0x10,
3668 .stmin = 3,
3669 .wftmax = 0,
3670 };
3671 if (setsockopt(fd, SOL_CAN_ISOTP, CAN_ISOTP_RECV_FC, &fcopts, sizeof(fcopts)) < 0) {
3672 perror("setsockopt");
3673 goto fail;
3674 }
3675
3676 struct can_isotp_options opts;
3677 (void)memset(&opts, 0, sizeof(opts));
3678
3679 if (functional) {
3680 // configure the socket as listen-only to avoid sending FC frames
3681 opts.flags |= CAN_ISOTP_LISTEN_MODE;
3682 }
3683
3684 if (setsockopt(fd, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts)) < 0) {
3685 perror("setsockopt (isotp_options):");
3686 goto fail;
3687 }
3688
3689 struct ifreq ifr;
3690 (void)memset(&ifr, 0, sizeof(ifr));
3691 if (snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", if_name) >= (int)sizeof(ifr.ifr_name)) {
3692 UDS_LOGE(__FILE__, "Interface name too long");
3693 goto fail;
3694 }
3695 ioctl(fd, SIOCGIFINDEX, &ifr);
3696
3697 struct sockaddr_can addr;
3698 (void)memset(&addr, 0, sizeof(addr));
3699 addr.can_family = AF_CAN;
3700 addr.can_addr.tp.rx_id = rxid;
3701 addr.can_addr.tp.tx_id = txid;
3702 addr.can_ifindex = ifr.ifr_ifindex;
3703
3704 if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
3705 UDS_LOGE(__FILE__, "Bind: %s %s", strerror(errno), if_name);
3706 goto fail;
3707 }
3708 return fd;
3709
3710fail:
3711 if (close(fd) < 0) {
3712 perror("close");
3713 }
3714 return -1;
3715}
3716
3717UDSErr_t UDSServerTpIsoTpSockInit(UDSTpIsoTpSock_t *tp, const char *ifname, uint32_t source_addr,
3718 uint32_t target_addr, uint32_t source_addr_func) {
3719 UDS_ASSERT(tp);
3720 (void)memset(tp, 0, sizeof(*tp));
3721 tp->hdl.send = isotp_sock_tp_send;
3722 tp->hdl.recv = isotp_sock_tp_recv;
3723 tp->hdl.poll = isotp_sock_tp_poll;
3724 tp->phys_sa = source_addr;
3725 tp->phys_ta = target_addr;
3726 tp->func_sa = source_addr_func;
3727
3728 tp->phys_fd = LinuxSockBind(ifname, source_addr, target_addr, false);
3729 if (tp->phys_fd < 0) {
3730 return UDS_FAIL;
3731 }
3732 tp->func_fd = LinuxSockBind(ifname, source_addr_func, 0, true);
3733 if (tp->func_fd < 0) {
3734 return UDS_FAIL;
3735 }
3736 const char *tag = "server";
3737 (void)memmove(tp->tag, tag, strlen(tag));
3738 UDS_LOGI(__FILE__, "%s initialized phys link rx 0x%03x tx 0x%03x func link rx 0x%03x tx 0x%03x",
3739 strlen(tp->tag) ? tp->tag : "server", source_addr, target_addr, source_addr_func,
3740 target_addr);
3741 return UDS_OK;
3742}
3743
3744UDSErr_t UDSClientTpIsoTpSockInit(UDSTpIsoTpSock_t *tp, const char *ifname, uint32_t source_addr,
3745 uint32_t target_addr, uint32_t target_addr_func) {
3746 UDS_ASSERT(tp);
3747 (void)memset(tp, 0, sizeof(*tp));
3748 tp->hdl.send = isotp_sock_tp_send;
3749 tp->hdl.recv = isotp_sock_tp_recv;
3750 tp->hdl.poll = isotp_sock_tp_poll;
3751 tp->func_ta = target_addr_func;
3752 tp->phys_ta = target_addr;
3753 tp->phys_sa = source_addr;
3754
3755 tp->phys_fd = LinuxSockBind(ifname, source_addr, target_addr, false);
3756 tp->func_fd = LinuxSockBind(ifname, 0, target_addr_func, true);
3757 if ((tp->phys_fd < 0) || (tp->func_fd < 0)) {
3758 return UDS_FAIL;
3759 }
3760 const char *tag = "client";
3761 (void)memmove(tp->tag, tag, strlen(tag));
3762 UDS_LOGI(__FILE__,
3763 "%s initialized phys link (fd %d) rx 0x%03x tx 0x%03x func link (fd %d) rx 0x%03x tx "
3764 "0x%03x",
3765 strlen(tp->tag) ? tp->tag : "client", tp->phys_fd, source_addr, target_addr,
3766 tp->func_fd, source_addr, target_addr_func);
3767 return UDS_OK;
3768}
3769
3771 if (tp != NULL) {
3772 if (close(tp->phys_fd) < 0) {
3773 perror("failed to close phys socket");
3774 }
3775 if (close(tp->func_fd) < 0) {
3776 perror("failed to close func socket");
3777 }
3778 }
3779}
3780
3781#endif
3782
3783#ifdef UDS_TP_ISOTP_MOCK
3784#ifdef UDS_LINES
3785#line 1 "src/tp/isotp_mock.c"
3786#endif // #ifdef UDS_LINES
3787
3788/// \cond INTERNAL_INTERFACE
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798#define MAX_NUM_TP 16U
3799#define NUM_MSGS 8U
3800static ISOTPMock_t TPs[MAX_NUM_TP];
3801static const char ZeroTestBlock[sizeof(ISOTPMock_t)] = {0};
3802static unsigned TPCount = 0;
3803static FILE *LogFile = NULL;
3804static struct Msg {
3805 uint8_t buf[UDS_ISOTP_MTU];
3806 size_t len;
3807 UDSSDU_t info;
3808 uint32_t scheduled_tx_time;
3809 ISOTPMock_t *sender;
3810} msgs[NUM_MSGS];
3811static unsigned MsgCount = 0;
3812
3813static void NetworkPoll(void) {
3814 unsigned i = 0;
3815 while (i < MsgCount) {
3816 if (UDSTimeAfter(UDSMillis(), msgs[i].scheduled_tx_time)) {
3817 bool found = false;
3818 for (unsigned j = 0; j < MAX_NUM_TP; j++) {
3819 ISOTPMock_t *tp = &TPs[j];
3820 if (0 == memcmp(tp, ZeroTestBlock, sizeof(ISOTPMock_t))) {
3821 continue; // slot not in use
3822 }
3823 if ((tp->sa_phys == msgs[i].info.A_TA) || (tp->sa_func == msgs[i].info.A_TA)) {
3824 found = true;
3825 if (tp->recv_len > 0U) {
3826 UDS_LOGW(__FILE__,
3827 "TPMock: %s recv buffer is already full. Message dropped",
3828 tp->name);
3829 continue;
3830 }
3831
3832 UDS_LOGD(__FILE__,
3833 "%s receives %ld bytes from TA=0x%03X (A_TA_Type=%s):", tp->name,
3834 msgs[i].len, msgs[i].info.A_TA,
3835 (msgs[i].info.A_TA_Type == UDS_A_TA_TYPE_PHYSICAL) ? "PHYSICAL"
3836 : "FUNCTIONAL");
3837 UDS_LOG_SDU(__FILE__, msgs[i].buf, msgs[i].len, &(msgs[i].info));
3838
3839 (void)memmove(tp->recv_buf, msgs[i].buf, msgs[i].len);
3840 tp->recv_len = msgs[i].len;
3841 tp->recv_info = msgs[i].info;
3842 }
3843 }
3844
3845 if (!found) {
3846 UDS_LOGW(__FILE__, "TPMock: no matching receiver for message");
3847 }
3848
3849 for (unsigned j = i + 1U; j < MsgCount; j++) {
3850 msgs[j - 1U] = msgs[j];
3851 }
3852 MsgCount--;
3853 } else {
3854 i++;
3855 }
3856 }
3857}
3858
3859static UDSErr_t mock_tp_send(struct UDSTp *hdl, const uint8_t *buf, size_t len,
3860 const UDSSDU_t *info) {
3861 UDS_ASSERT(hdl);
3862 ISOTPMock_t *tp = (ISOTPMock_t *)hdl; // cppcheck-suppress [misra-c2012-11.3]
3863 if (MsgCount >= NUM_MSGS) {
3864 UDS_LOGW(__FILE__, "mock_tp_send: too many messages in the queue");
3865 return UDS_FAIL;
3866 }
3867 struct Msg *m = &msgs[MsgCount];
3868 MsgCount++;
3869 UDS_A_TA_Type_t ta_type =
3870 (info == NULL) ? (UDS_A_TA_Type_t)UDS_A_TA_TYPE_PHYSICAL : (UDS_A_TA_Type_t)info->A_TA_Type;
3871 m->len = len;
3872 m->info.A_AE = (info == NULL) ? 0U : info->A_AE;
3873 if (UDS_A_TA_TYPE_PHYSICAL == ta_type) {
3874 m->info.A_TA = tp->ta_phys;
3875 m->info.A_SA = tp->sa_phys;
3876 } else if (UDS_A_TA_TYPE_FUNCTIONAL == ta_type) {
3877
3878 // This condition is only true for standard CAN.
3879 // Technically CAN-FD may also be used in ISO-TP.
3880 // TODO: add profiles to isotp_mock
3881 if (len > 7U) {
3882 UDS_LOGW(__FILE__, "mock_tp_send: functional message too long: %zu", len);
3883 return UDS_FAIL;
3884 }
3885 m->info.A_TA = tp->ta_func;
3886 m->info.A_SA = tp->sa_func;
3887 } else {
3888 UDS_LOGW(__FILE__, "mock_tp_send: unknown TA type: %d", ta_type);
3889 return UDS_FAIL;
3890 }
3891 m->info.A_TA_Type = ta_type;
3892 m->scheduled_tx_time = UDSMillis() + tp->send_tx_delay_ms;
3893 (void)memmove(m->buf, buf, len);
3894
3895 UDS_LOGD(__FILE__, "%s sends %ld bytes to TA=0x%03X (A_TA_Type=%s):", tp->name, len,
3896 m->info.A_TA,
3897 (m->info.A_TA_Type == UDS_A_TA_TYPE_PHYSICAL) ? "PHYSICAL" : "FUNCTIONAL");
3898 UDS_LOG_SDU(__FILE__, buf, len, &m->info);
3899
3900 return UDS_OK;
3901}
3902
3903static UDSErr_t mock_tp_recv(struct UDSTp *hdl, uint8_t *buf, size_t bufsiz, size_t *recvlen,
3904 UDSSDU_t *info) {
3905 UDS_ASSERT(hdl);
3906 ISOTPMock_t *tp = (ISOTPMock_t *)hdl; // cppcheck-suppress [misra-c2012-11.3]
3907 if (tp->recv_len == 0U) {
3908 return UDS_OK;
3909 }
3910 if (bufsiz < tp->recv_len) {
3911 UDS_LOGE(__FILE__, "mock_tp_recv: buffer too small: %ld < %ld", bufsiz, tp->recv_len);
3912 return UDS_FAIL;
3913 }
3914 *recvlen = tp->recv_len;
3915 (void)memmove(buf, tp->recv_buf, tp->recv_len);
3916 if (info != NULL) {
3917 *info = tp->recv_info;
3918 }
3919 tp->recv_len = 0;
3920 return UDS_OK;
3921}
3922
3923static UDSErr_t mock_tp_poll(struct UDSTp *hdl) {
3924 (void)hdl; // unused parameter
3925 NetworkPoll();
3926 return UDS_OK;
3927}
3928
3929static void ISOTPMockAttach(ISOTPMock_t *tp, const ISOTPMockArgs_t *args) {
3930 UDS_ASSERT(tp);
3931 UDS_ASSERT(args);
3932 UDS_ASSERT(TPCount < MAX_NUM_TP);
3933 TPCount++;
3934 tp->hdl.send = mock_tp_send;
3935 tp->hdl.recv = mock_tp_recv;
3936 tp->hdl.poll = mock_tp_poll;
3937 tp->sa_func = args->sa_func;
3938 tp->sa_phys = args->sa_phys;
3939 tp->ta_func = args->ta_func;
3940 tp->ta_phys = args->ta_phys;
3941 tp->recv_len = 0;
3942 UDS_LOGV(__FILE__, "attached %s. TPCount: %d", tp->name, TPCount);
3943}
3944
3945static void ISOTPMockDetach(ISOTPMock_t *tp) {
3946 UDS_ASSERT(tp);
3947 for (unsigned i = 0; i < MAX_NUM_TP; i++) {
3948 if (&TPs[i] == tp) {
3949 TPCount--;
3950 UDS_LOGV(__FILE__, "TPMock: detached %s. TPCount: %d", tp->name, TPCount);
3951 return;
3952 }
3953 }
3954 UDS_ASSERT(false);
3955}
3956
3957UDSTp_t *ISOTPMockNew(const char *name, const ISOTPMockArgs_t *args) {
3958 if (TPCount >= MAX_NUM_TP) {
3959 UDS_LOGI(__FILE__, "TPCount: %d, too many TPs\n", TPCount);
3960 return NULL;
3961 }
3962 size_t i = 0;
3963 do {
3964 if (0 == memcmp(&TPs[i], ZeroTestBlock, sizeof(ISOTPMock_t))) {
3965 break;
3966 }
3967 i++;
3968 } while (i < MAX_NUM_TP);
3969 UDS_ASSERT(i != MAX_NUM_TP);
3970 ISOTPMock_t *tp = &TPs[i];
3971 UDS_ASSERT(tp);
3972 (void)memset(tp, 0, sizeof(ISOTPMock_t));
3973 if (name != NULL) {
3974 if (snprintf(tp->name, sizeof(tp->name), "%s", name) >= (int)sizeof(tp->name)) {
3975 UDS_LOGE(__FILE__, "Transport name too long, truncated");
3976 }
3977 } else {
3978 (void)snprintf(tp->name, sizeof(tp->name), "TPMock%u", TPCount);
3979 }
3980 ISOTPMockAttach(tp, args);
3981 return &tp->hdl;
3982}
3983
3984void ISOTPMockConnect(UDSTp_t *tp1, UDSTp_t *tp2);
3985
3986void ISOTPMockLogToFile(const char *filename) {
3987 if (LogFile != NULL) {
3988 (void)fprintf(stderr, "Log file is already open\n");
3989 return;
3990 }
3991 if (!filename) {
3992 (void)fprintf(stderr, "Filename is NULL\n");
3993 return;
3994 }
3995 // create file
3996 LogFile = fopen(filename, "w");
3997 if (NULL == LogFile) {
3998 (void)fprintf(stderr, "Failed to open log file %s\n", filename);
3999 return;
4000 }
4001}
4002
4003void ISOTPMockLogToStdout(void) {
4004 if (NULL == LogFile) {
4005 return;
4006 }
4007 LogFile = stdout;
4008}
4009
4010void ISOTPMockReset(void) {
4011 (void)memset(TPs, 0, sizeof(TPs));
4012 TPCount = 0;
4013 (void)memset(msgs, 0, sizeof(msgs));
4014 MsgCount = 0;
4015}
4016
4017void ISOTPMockFree(UDSTp_t *tp) {
4018 UDS_ASSERT(tp);
4019 UDS_ASSERT(0 != memcmp(tp, ZeroTestBlock, sizeof(ISOTPMock_t)));
4020 ISOTPMock_t *tpm = (ISOTPMock_t *)tp; // cppcheck-suppress [misra-c2012-11.3]
4021 ISOTPMockDetach(tpm);
4022 (void)memset(tp, 0, sizeof(ISOTPMock_t));
4023}
4024
4025/// \endcond INTERNAL_INTERFACE
4026
4027#endif
4028
4029#if defined(UDS_TP_ISOTP_C)
4030/// \cond DOXYGEN_SHOULD_SKIP_THIS
4031
4032#ifndef ISO_TP_USER_SEND_CAN_ARG
4033#error "need this"
4034#endif
4035
4036#ifndef ISO_TP_NO_FORMATTED_ERRORS
4037#error "need this too"
4038#endif
4039
4040////////////////////////////////////////////////////////////////////////
4041#ifdef UDS_LINES
4042#line 1 "src/tp/isotp-c/isotp.c"
4043#endif // #ifdef UDS_LINES
4044// ___ ___ ___ _____ ___ ___ //
4045// |_ _/ __|/ _ \_ _| _ \___ / __| //
4046// | |\__ \ (_) || | | _/___| (__ //
4047// |___|___/\___/ |_| |_| \___| //
4048// //
4049////////////////////////////////////////////////////////////////////////
4050
4051
4052
4053
4054
4055
4056///////////////////////////////////////////////////////
4057/// STATIC FUNCTIONS ///
4058///////////////////////////////////////////////////////
4059
4060/* CAN frame data lengths (CAN_DL) which may be used by CAN FD frames larger than
4061 * a Classical CAN frame. CAN FD frames can only carry these lengths, so frames
4062 * exceeding 8 bytes always have to be padded up to the next valid length.
4063 */
4064static const uint8_t isotp_can_fd_frame_sizes[] = {12, 16, 20, 24, 32, 48, 64};
4065
4066/* Returns the smallest valid CAN_DL which is able to carry length bytes of data */
4067static uint8_t isotp_ceil_can_dl(uint8_t length) {
4068 if (length <= ISOTP_CAN_DL_CLASSIC) {
4069 /* every length up to 8 bytes maps directly to a DLC */
4070 return length;
4071 }
4072
4073 for (uint8_t i = 0; i < (uint8_t)(sizeof(isotp_can_fd_frame_sizes) / sizeof(isotp_can_fd_frame_sizes[0])); ++i) {
4074 if (length <= isotp_can_fd_frame_sizes[i]) { return isotp_can_fd_frame_sizes[i]; }
4075 }
4076
4077 return isotp_can_fd_frame_sizes[sizeof(isotp_can_fd_frame_sizes) / sizeof(isotp_can_fd_frame_sizes[0]) - 1];
4078}
4079
4080/* Returns logic true if length is a CAN_DL which can be transmitted on a CAN(-FD) bus */
4081static uint8_t isotp_is_valid_can_dl(uint8_t length) { return (uint8_t)(length == isotp_ceil_can_dl(length)); }
4082
4083/* Returns the TX_DL to use for the given link, falling back to Classical CAN for
4084 * links which weren't initialised through isotp_init_link()
4085 */
4086static uint8_t isotp_tx_dl(const IsoTpLink* link) {
4087 if (link->tx_dl < ISOTP_CAN_DL_CLASSIC || link->tx_dl > ISO_TP_MAX_CAN_FRAME_SIZE || !isotp_is_valid_can_dl(link->tx_dl)) { return ISOTP_CAN_DL_CLASSIC; }
4088
4089 return link->tx_dl;
4090}
4091
4092#ifdef ISO_TP_USER_SEND_CAN_FLAGS
4093/* Returns the frame format flags the user shim has to transmit the frames of this link with.
4094 * Links using a TX_DL of more than 8 bytes require CAN FD frames, so all of their frames are
4095 * flagged accordingly, irrespective of the length of the individual frame.
4096 */
4097static uint8_t isotp_frame_flags(const IsoTpLink* link) {
4098 uint8_t flags = ISOTP_CAN_FRAME_FLAG_NONE;
4099
4100 if (isotp_tx_dl(link) > ISOTP_CAN_DL_CLASSIC) {
4101 flags |= ISOTP_CAN_FRAME_FLAG_FD;
4102
4103 #ifdef ISO_TP_CAN_FD_USE_BRS
4104 flags |= ISOTP_CAN_FRAME_FLAG_BRS;
4105 #endif
4106 }
4107
4108 return flags;
4109}
4110#endif
4111
4112/* Pads a frame containing used_length bytes up to a transmittable CAN_DL and
4113 * returns the resulting frame length.
4114 *
4115 * Frames of more than 8 bytes are always padded, as CAN FD only supports a
4116 * discrete set of frame lengths. Smaller frames are only padded if
4117 * ISO_TP_FRAME_PADDING is enabled.
4118 */
4119static uint8_t isotp_pad_frame(IsoTpCanMessage* message, uint8_t used_length) {
4120 uint8_t frame_length = used_length;
4121
4122#ifdef ISO_TP_FRAME_PADDING
4123 if (frame_length < ISOTP_CAN_DL_CLASSIC) { frame_length = ISOTP_CAN_DL_CLASSIC; }
4124#endif
4125
4126 frame_length = isotp_ceil_can_dl(frame_length);
4127
4128 if (frame_length > used_length) { (void)memset(message->as.data_array.ptr + used_length, ISO_TP_FRAME_PADDING_VALUE, frame_length - used_length); }
4129
4130 return frame_length;
4131}
4132
4133/* st_min to microsecond */
4134static uint8_t isotp_us_to_st_min(uint32_t us) {
4135 // ISO 15765-2:2016 defines STmin encoding:
4136 // 0x00..0x7F: value in milliseconds (0..127 ms)
4137 // 0xF1..0xF9: value in 100 microsecond steps (100..900 us)
4138 const uint32_t STMIN_MS_MAX = 127000; // 127 ms in us
4139 const uint32_t STMIN_US_MIN = 100; // 100 us
4140 const uint32_t STMIN_US_MAX = 900; // 900 us
4141 const uint8_t STMIN_US_BASE = 0xF0; // base for 100us steps
4142
4143 if (us <= STMIN_MS_MAX) {
4144 if (us >= STMIN_US_MIN && us <= STMIN_US_MAX) {
4145 return (uint8_t)(STMIN_US_BASE + (us / 100));
4146 } else {
4147 return (uint8_t)(us / 1000u);
4148 }
4149 }
4150
4151 return 0;
4152}
4153
4154/* st_min to usec */
4155static uint32_t isotp_st_min_to_us(uint8_t st_min) {
4156 // ISO 15765-2:2016 defines STmin encoding:
4157 // 0x00..0x7F: value in milliseconds (0..127 ms)
4158 // 0xF1..0xF9: value in 100 microsecond steps (100..900 us)
4159 const uint8_t STMIN_MS_MAX = 0x7F; // 127 ms
4160 const uint8_t STMIN_US_MIN_CODE = 0xF1; // 100 us
4161 const uint8_t STMIN_US_MAX_CODE = 0xF9; // 900 us
4162 const uint8_t STMIN_US_BASE = 0xF0; // base for 100us steps
4163 const uint32_t US_PER_MS = 1000;
4164 const uint32_t US_STEP = 100;
4165
4166 if (st_min <= STMIN_MS_MAX) {
4167 return st_min * US_PER_MS;
4168 } else if (st_min >= STMIN_US_MIN_CODE && st_min <= STMIN_US_MAX_CODE) {
4169 return (st_min - STMIN_US_BASE) * US_STEP;
4170 }
4171 return 0;
4172}
4173
4174static int isotp_send_flow_control(const IsoTpLink* link, uint8_t flow_status, uint8_t block_size, uint32_t st_min_us) {
4175 IsoTpCanMessage message;
4176 (void)memset(&message, 0, sizeof(message));
4177 int ret;
4178 uint8_t size = 0;
4179
4180 /* setup message */
4181 message.as.flow_control.type = ISOTP_PCI_TYPE_FLOW_CONTROL_FRAME;
4182 message.as.flow_control.FS = flow_status;
4183 message.as.flow_control.BS = block_size;
4184 message.as.flow_control.STmin = isotp_us_to_st_min(st_min_us);
4185
4186 /* send message */
4187 size = isotp_pad_frame(&message, 3);
4188
4189 ret = isotp_user_send_can(link->send_arbitration_id, message.as.data_array.ptr, size
4190#if defined(ISO_TP_USER_SEND_CAN_FLAGS)
4191 , isotp_frame_flags(link)
4192#endif
4193#if defined(ISO_TP_USER_SEND_CAN_ARG)
4194 , link->user_send_can_arg
4195#endif
4196 );
4197
4198 return ret;
4199}
4200
4201static int isotp_send_single_frame(const IsoTpLink* link, uint32_t id) {
4202 IsoTpCanMessage message;
4203 int ret;
4204 uint8_t size = 0;
4205
4206 (void)memset(&message, 0, sizeof(message));
4207
4208 /* payloads which don't fit into a single frame must be segmented */
4209 assert(link->send_size <= ISOTP_SF_MAX_PAYLOAD(isotp_tx_dl(link)));
4210
4211 /* setup message */
4212 if (link->send_size < ISOTP_CAN_DL_CLASSIC) {
4213 message.as.single_frame.type = ISOTP_PCI_TYPE_SINGLE;
4214 message.as.single_frame.SF_DL = (uint8_t)link->send_size;
4215 (void)memcpy(message.as.single_frame.data, link->send_buffer, link->send_size);
4216
4217 size = isotp_pad_frame(&message, (uint8_t)(link->send_size + 1u));
4218 } else { // ISO15765-2:2016, CAN FD only
4219 /* setup message using the SF_DL escape sequence */
4220 message.as.single_frame_escape.type = ISOTP_PCI_TYPE_SINGLE;
4221 message.as.single_frame_escape.set_to_zero = 0;
4222 message.as.single_frame_escape.SF_DL = (uint8_t)link->send_size;
4223 (void)memcpy(message.as.single_frame_escape.data, link->send_buffer, link->send_size);
4224
4225 size = isotp_pad_frame(&message, (uint8_t)(link->send_size + 2u));
4226 }
4227
4228 /* send message using the identifier requested by the caller, which
4229 * isotp_send_with_id() may override for a functional request */
4230 ret = isotp_user_send_can(id, message.as.data_array.ptr, size
4231#if defined(ISO_TP_USER_SEND_CAN_FLAGS)
4232 , isotp_frame_flags(link)
4233#endif
4234#if defined(ISO_TP_USER_SEND_CAN_ARG)
4235 , link->user_send_can_arg
4236#endif
4237 );
4238
4239 return ret;
4240}
4241static int isotp_send_first_frame(IsoTpLink* link, uint32_t id) {
4242 IsoTpCanMessage message;
4243 int ret = 0;
4244 const uint8_t tx_dl = isotp_tx_dl(link);
4245 uint32_t data_length;
4246
4247 (void)memset(&message, 0, sizeof(message));
4248
4249 /* payloads which fit into a single frame must not be segmented */
4250 assert(link->send_size > ISOTP_SF_MAX_PAYLOAD(tx_dl));
4251
4252 /* first frames always use the full frame length of the sender (TX_DL) */
4253 if (link->send_size <= 4095) {
4254 /* setup 'short' message */
4255 data_length = (uint32_t)tx_dl - 2u;
4256 message.as.first_frame_short.type = ISOTP_PCI_TYPE_FIRST_FRAME;
4257 message.as.first_frame_short.FF_DL_low = (uint8_t)link->send_size;
4258 message.as.first_frame_short.FF_DL_high = (uint8_t)(0x0F & (link->send_size >> 8));
4259 (void)memcpy(message.as.first_frame_short.data, link->send_buffer, data_length);
4260 } else { // ISO15765-2:2016
4261 /* setup 'long' message */
4262 data_length = (uint32_t)tx_dl - 6u;
4263 message.as.first_frame_long.set_to_zero_high = 0;
4264 message.as.first_frame_long.set_to_zero_low = 0;
4265 message.as.first_frame_long.type = ISOTP_PCI_TYPE_FIRST_FRAME;
4266 message.as.first_frame_long.FF_DL = LE32TOH(link->send_size);
4267 (void)memcpy(message.as.first_frame_long.data, link->send_buffer, data_length);
4268 }
4269
4270 /* send message */
4271 ret = isotp_user_send_can(id, message.as.data_array.ptr, tx_dl
4272#if defined(ISO_TP_USER_SEND_CAN_FLAGS)
4273 , isotp_frame_flags(link)
4274#endif
4275#if defined(ISO_TP_USER_SEND_CAN_ARG)
4276 , link->user_send_can_arg
4277#endif
4278 );
4279
4280 if (ISOTP_RET_OK == ret) { link->send_offset += data_length; }
4281
4282 link->send_sn = 1;
4283
4284 return ret;
4285}
4286
4287static int isotp_send_consecutive_frame(IsoTpLink* link) {
4288 IsoTpCanMessage message;
4289 uint32_t data_length;
4290 uint32_t max_data_length;
4291 int ret;
4292 uint8_t size = 0;
4293
4294 (void)memset(&message, 0, sizeof(message));
4295
4296 /* payloads which fit into a single frame must not be segmented */
4297 assert(link->send_size > ISOTP_SF_MAX_PAYLOAD(isotp_tx_dl(link)));
4298
4299 /* setup message */
4300 message.as.consecutive_frame.type = ISOTP_PCI_TYPE_CONSECUTIVE_FRAME;
4301 message.as.consecutive_frame.SN = link->send_sn;
4302 max_data_length = (uint32_t)isotp_tx_dl(link) - 1u;
4303 data_length = link->send_size - link->send_offset;
4304 if (data_length > max_data_length) { data_length = max_data_length; }
4305 (void)memcpy(message.as.consecutive_frame.data, link->send_buffer + link->send_offset, data_length);
4306
4307 /* send message */
4308 size = isotp_pad_frame(&message, (uint8_t)(data_length + 1u));
4309
4310 ret = isotp_user_send_can(link->send_arbitration_id, message.as.data_array.ptr, size
4311#if defined(ISO_TP_USER_SEND_CAN_FLAGS)
4312 , isotp_frame_flags(link)
4313#endif
4314#if defined(ISO_TP_USER_SEND_CAN_ARG)
4315 , link->user_send_can_arg
4316#endif
4317 );
4318
4319 if (ISOTP_RET_OK == ret) {
4320 link->send_offset += data_length;
4321 if (++(link->send_sn) > 0x0F) { link->send_sn = 0; }
4322 }
4323
4324 return ret;
4325}
4326
4327static int isotp_receive_single_frame(IsoTpLink* link, const IsoTpCanMessage* message, uint8_t len) {
4328 const uint8_t* payload;
4329 uint32_t payload_length;
4330 uint32_t max_payload_length;
4331
4332 if (0 == message->as.single_frame.SF_DL) {
4333 /* ISO15765-2:2016: CAN FD frames larger than 8 bytes carry SF_DL in the second byte */
4334 if (len <= ISOTP_CAN_DL_CLASSIC) {
4335 isotp_user_debug("Single-frame length too small.");
4336 return ISOTP_RET_LENGTH;
4337 }
4338
4339 payload = message->as.single_frame_escape.data;
4340 payload_length = message->as.single_frame_escape.SF_DL;
4341 max_payload_length = (uint32_t)len - 2u;
4342 } else {
4343 payload = message->as.single_frame.data;
4344 payload_length = message->as.single_frame.SF_DL;
4345 max_payload_length = (uint32_t)len - 1u;
4346 }
4347
4348 /* check data length */
4349 if ((0 == payload_length) || (payload_length > max_payload_length)) {
4350 isotp_user_debug("Single-frame length too small.");
4351 return ISOTP_RET_LENGTH;
4352 }
4353
4354 if (payload_length > link->receive_buf_size) {
4355 isotp_user_debug("Single-frame message too large for receiving buffer.");
4356 return ISOTP_RET_OVERFLOW;
4357 }
4358
4359 /* copying data */
4360 (void)memcpy(link->receive_buffer, payload, payload_length);
4361 link->receive_size = payload_length;
4362 link->receive_offset = link->receive_size;
4363
4364#ifdef ISO_TP_ENABLE_STREAMING
4365 link->receive_stream_size = link->receive_size;
4366 link->receive_streaming = 0;
4367 link->receive_stream_carry_size = 0;
4368#endif
4369
4370 return ISOTP_RET_OK;
4371}
4372
4373static int isotp_receive_first_frame(IsoTpLink* link, IsoTpCanMessage* message, uint8_t len) {
4374 const uint8_t* first_frame_data;
4375 uint8_t is_long_packet = 0;
4376 uint32_t first_frame_data_length;
4377 uint32_t payload_length;
4378
4379 /* first frames are sent using the full frame length of the sender, which
4380 * determines the frame length of the following consecutive frames (RX_DL)
4381 */
4382 if (len < ISOTP_CAN_DL_CLASSIC || !isotp_is_valid_can_dl(len)) {
4383 isotp_user_debug("First frame should be a full CAN frame of at least 8 bytes in length.");
4384 return ISOTP_RET_LENGTH;
4385 }
4386
4387 /* check data length */
4388 payload_length = message->as.first_frame_short.FF_DL_high;
4389 payload_length = (payload_length << 8) + message->as.first_frame_short.FF_DL_low;
4390
4391 /* if length is ZERO we get a long message > 4095bytes of payload */
4392 if (payload_length == 0) {
4393 is_long_packet = 1;
4394 payload_length = LE32TOH(message->as.first_frame_long.FF_DL);
4395 first_frame_data_length = (uint32_t)len - 6u;
4396 } else {
4397 first_frame_data_length = (uint32_t)len - 2u;
4398 }
4399
4400 /* should not use multiple frame transmition */
4401 if (payload_length <= ISOTP_SF_MAX_PAYLOAD(len)) {
4402 isotp_user_debug("Should not use multiple frame transmission.");
4403 return ISOTP_RET_LENGTH;
4404 }
4405
4406#ifndef ISO_TP_ENABLE_STREAMING
4407 if (payload_length > link->receive_buf_size) {
4408 isotp_user_debug("Multi-frame response too large for receiving buffer.");
4409 return ISOTP_RET_OVERFLOW;
4410 }
4411#else
4412 if (link->receive_buf_size == 0) {
4413 isotp_user_debug("Receiving buffer must not be empty.");
4414 return ISOTP_RET_OVERFLOW;
4415 }
4416
4417 link->receive_streaming = payload_length > link->receive_buf_size;
4418 link->receive_stream_size = 0;
4419 link->receive_stream_carry_size = 0;
4420#endif
4421
4422 /* copying data */
4423 if (is_long_packet) {
4424 first_frame_data = message->as.first_frame_long.data;
4425 } else {
4426 first_frame_data = message->as.first_frame_short.data;
4427 }
4428
4429#ifdef ISO_TP_ENABLE_STREAMING
4430 if (first_frame_data_length > link->receive_buf_size) {
4431 (void)memcpy(link->receive_buffer, first_frame_data, link->receive_buf_size);
4432 link->receive_stream_size = link->receive_buf_size;
4433 link->receive_stream_carry_size = (uint8_t)(first_frame_data_length - link->receive_buf_size);
4434 (void)memcpy(link->receive_stream_carry, first_frame_data + link->receive_buf_size, link->receive_stream_carry_size);
4435 } else {
4436 (void)memcpy(link->receive_buffer, first_frame_data, first_frame_data_length);
4437 link->receive_stream_size = first_frame_data_length;
4438 }
4439#else
4440 (void)memcpy(link->receive_buffer, first_frame_data, first_frame_data_length);
4441#endif
4442
4443 link->receive_offset = first_frame_data_length;
4444 link->receive_size = payload_length;
4445 link->receive_sn = 1;
4446 link->rx_dl = len;
4447
4448 return ISOTP_RET_OK;
4449}
4450
4451static int isotp_receive_consecutive_frame(IsoTpLink* link, const IsoTpCanMessage* message, uint8_t len) {
4452 uint32_t remaining_bytes;
4453 uint32_t max_data_length;
4454
4455 /* check sn */
4456 if (link->receive_sn != message->as.consecutive_frame.SN) { return ISOTP_RET_WRONG_SN; }
4457
4458 /* consecutive frames use the frame length announced by the first frame (RX_DL) */
4459 max_data_length = (uint32_t)(link->rx_dl < ISOTP_CAN_DL_CLASSIC ? ISOTP_CAN_DL_CLASSIC : link->rx_dl) - 1u;
4460
4461 /* check data length */
4462 remaining_bytes = link->receive_size - link->receive_offset;
4463 if (remaining_bytes > max_data_length) { remaining_bytes = max_data_length; }
4464 if (remaining_bytes > (uint32_t)(len - 1)) {
4465 isotp_user_debug("Consecutive frame too short.");
4466 return ISOTP_RET_LENGTH;
4467 }
4468
4469#ifdef ISO_TP_ENABLE_STREAMING
4470 if (link->receive_streaming) {
4471 uint32_t available = link->receive_buf_size - link->receive_stream_size;
4472 uint32_t copy_size = remaining_bytes < available ? remaining_bytes : available;
4473
4474 (void)memcpy(link->receive_buffer + link->receive_stream_size, message->as.consecutive_frame.data, copy_size);
4475 link->receive_stream_size += copy_size;
4476
4477 link->receive_stream_carry_size = (uint8_t)(remaining_bytes - copy_size);
4478 if (link->receive_stream_carry_size > 0) {
4479 (void)memcpy(link->receive_stream_carry, message->as.consecutive_frame.data + copy_size, link->receive_stream_carry_size);
4480 }
4481 } else
4482#endif
4483 {
4484 /* copying data */
4485 (void)memcpy(link->receive_buffer + link->receive_offset, message->as.consecutive_frame.data, remaining_bytes);
4486 }
4487
4488 link->receive_offset += remaining_bytes;
4489 if (++(link->receive_sn) > 0x0F) { link->receive_sn = 0; }
4490
4491 return ISOTP_RET_OK;
4492}
4493
4494static int isotp_receive_flow_control_frame(IsoTpLink* link, IsoTpCanMessage* message, uint8_t len) {
4495 /* unused args */
4496 (void)link;
4497 (void)message;
4498
4499 /* check message length */
4500 if (len < 3) {
4501 isotp_user_debug("Flow control frame too short.");
4502 return ISOTP_RET_LENGTH;
4503 }
4504
4505 return ISOTP_RET_OK;
4506}
4507
4508///////////////////////////////////////////////////////
4509/// PUBLIC FUNCTIONS ///
4510///////////////////////////////////////////////////////
4511
4512int isotp_send(IsoTpLink* link, const uint8_t payload[], uint32_t size) { return isotp_send_with_id(link, link->send_arbitration_id, payload, size); }
4513
4514int isotp_send_with_id(IsoTpLink* link, uint32_t id, const uint8_t payload[], uint32_t size) {
4515 int ret;
4516
4517 if (link == 0x0) {
4518 isotp_user_debug("Link is null!");
4519 return ISOTP_RET_ERROR;
4520 }
4521
4522 if (size > link->send_buf_size) {
4523 isotp_user_debug("Message size too large. Increase ISO_TP_MAX_MESSAGE_SIZE to set a larger buffer\n");
4524
4525#ifndef ISO_TP_NO_FORMATTED_ERRORS
4526 char message[ISOTP_MAX_ERROR_MSG_SIZE] = {0};
4527 int32_t writtenChars = ISOTP_SNPRINTF(&message[0], ISOTP_MAX_ERROR_MSG_SIZE, "Attempted to send %u bytes; max size is %u!\n", (unsigned int)size,
4528 (unsigned int)link->send_buf_size);
4529
4530 assert(writtenChars <= ISOTP_MAX_ERROR_MSG_SIZE);
4531 (void)writtenChars;
4532
4533 isotp_user_debug(message);
4534#endif
4535 return ISOTP_RET_OVERFLOW;
4536 }
4537
4538 if (ISOTP_SEND_STATUS_INPROGRESS == link->send_status) {
4539 isotp_user_debug("Abort previous message, transmission in progress.\n");
4540 return ISOTP_RET_INPROGRESS;
4541 }
4542
4543 /* copy into local buffer */
4544 link->send_size = size;
4545 link->send_offset = 0;
4546 (void)memcpy(link->send_buffer, payload, size);
4547
4548 if (link->send_size <= ISOTP_SF_MAX_PAYLOAD(isotp_tx_dl(link))) {
4549 /* send single frame */
4550 ret = isotp_send_single_frame(link, id);
4551#ifdef ISO_TP_TRANSMIT_COMPLETE_CALLBACK
4552 if (ret == ISOTP_RET_OK && link->tx_done_cb) { link->tx_done_cb(link, link->send_size, link->tx_done_cb_arg); }
4553#endif
4554 } else {
4555 /* send multi-frame */
4556 ret = isotp_send_first_frame(link, id);
4557
4558 /* init multi-frame control flags */
4559 if (ISOTP_RET_OK == ret) {
4560 link->send_bs_remain = 0;
4561 link->send_st_min_us = 0;
4562 link->send_wtf_count = 0;
4563 link->send_timer_st = isotp_user_get_us();
4564 link->send_timer_bs = isotp_user_get_us() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT_US;
4565 link->send_protocol_result = ISOTP_PROTOCOL_RESULT_OK;
4566 link->send_status = ISOTP_SEND_STATUS_INPROGRESS;
4567 }
4568 }
4569
4570 return ret;
4571}
4572
4573void isotp_on_can_message(IsoTpLink* link, const uint8_t* data, uint8_t len) {
4574 IsoTpCanMessage message;
4575 int ret;
4576
4577 if (len < 2 || len > ISO_TP_MAX_CAN_FRAME_SIZE) { return; }
4578
4579 memcpy(message.as.data_array.ptr, data, len);
4580 memset(message.as.data_array.ptr + len, 0, sizeof(message.as.data_array.ptr) - len);
4581
4582 switch (message.as.common.type) {
4583 case ISOTP_PCI_TYPE_SINGLE: {
4584 /* update protocol result */
4585 if (ISOTP_RECEIVE_STATUS_INPROGRESS == link->receive_status) {
4586 link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_UNEXP_PDU;
4587 } else {
4588 link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_OK;
4589 }
4590
4591 /* handle message */
4592 ret = isotp_receive_single_frame(link, &message, len);
4593
4594 if (ISOTP_RET_OVERFLOW == ret) {
4595 /* update protocol result */
4596 link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_BUFFER_OVFLW;
4597 } else if (ISOTP_RET_OK == ret) {
4598 /* change status */
4599 link->receive_status = ISOTP_RECEIVE_STATUS_FULL;
4600 }
4601 break;
4602 }
4603 case ISOTP_PCI_TYPE_FIRST_FRAME: {
4604 /* update protocol result */
4605 if (ISOTP_RECEIVE_STATUS_INPROGRESS == link->receive_status) {
4606 link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_UNEXP_PDU;
4607 } else {
4608 link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_OK;
4609 }
4610
4611 /* handle message */
4612 ret = isotp_receive_first_frame(link, &message, len);
4613
4614 /* if overflow happened */
4615 if (ISOTP_RET_OVERFLOW == ret) {
4616 /* update protocol result */
4617 link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_BUFFER_OVFLW;
4618 /* change status */
4619 link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
4620 /* send error message */
4621 isotp_send_flow_control(link, PCI_FLOW_STATUS_OVERFLOW, 0, 0);
4622 break;
4623 }
4624
4625 /* if receive successful */
4626 if (ISOTP_RET_OK == ret) {
4627 /* change status and send fc frame */
4628#ifdef ISO_TP_ENABLE_STREAMING
4629 if (link->receive_streaming && link->receive_stream_size >= link->receive_buf_size) {
4630 link->receive_status = ISOTP_RECEIVE_STATUS_FULL;
4631 } else {
4632 link->receive_status = ISOTP_RECEIVE_STATUS_INPROGRESS;
4633 link->receive_bs_count = link->receive_streaming ? 1 : ISO_TP_DEFAULT_BLOCK_SIZE;
4634 isotp_send_flow_control(link, PCI_FLOW_STATUS_CONTINUE, link->receive_bs_count, ISO_TP_DEFAULT_ST_MIN_US);
4635 }
4636#else
4637 link->receive_status = ISOTP_RECEIVE_STATUS_INPROGRESS;
4638 link->receive_bs_count = ISO_TP_DEFAULT_BLOCK_SIZE;
4639 isotp_send_flow_control(link, PCI_FLOW_STATUS_CONTINUE, link->receive_bs_count, ISO_TP_DEFAULT_ST_MIN_US);
4640#endif
4641 /* refresh timer cs */
4642 link->receive_timer_cr = isotp_user_get_us() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT_US;
4643 }
4644
4645 break;
4646 }
4647 case ISOTP_PCI_TYPE_CONSECUTIVE_FRAME: {
4648 /* check if in receiving status */
4649 if (ISOTP_RECEIVE_STATUS_INPROGRESS != link->receive_status) {
4650 link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_UNEXP_PDU;
4651 break;
4652 }
4653
4654 /* handle message */
4655 ret = isotp_receive_consecutive_frame(link, &message, len);
4656
4657 /* if wrong sn */
4658 if (ISOTP_RET_WRONG_SN == ret) {
4659 link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_WRONG_SN;
4660 link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
4661 break;
4662 }
4663
4664 /* if success */
4665 if (ISOTP_RET_OK == ret) {
4666 /* refresh timer cs */
4667 link->receive_timer_cr = isotp_user_get_us() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT_US;
4668
4669 /* receive finished */
4670 if (link->receive_offset >= link->receive_size
4671#ifdef ISO_TP_ENABLE_STREAMING
4672 || (link->receive_streaming && link->receive_stream_size >= link->receive_buf_size)
4673#endif
4674 ) {
4675 link->receive_status = ISOTP_RECEIVE_STATUS_FULL;
4676 } else {
4677 /* send fc when bs reaches limit */
4678 if (0 == --link->receive_bs_count) {
4679 link->receive_bs_count =
4680#ifdef ISO_TP_ENABLE_STREAMING
4681 link->receive_streaming ? 1 :
4682#endif
4683 ISO_TP_DEFAULT_BLOCK_SIZE;
4684 isotp_send_flow_control(link, PCI_FLOW_STATUS_CONTINUE, link->receive_bs_count, ISO_TP_DEFAULT_ST_MIN_US);
4685 }
4686 }
4687 }
4688
4689 break;
4690 }
4691 case ISOTP_PCI_TYPE_FLOW_CONTROL_FRAME:
4692 /* handle fc frame only when sending in progress */
4693 if (ISOTP_SEND_STATUS_INPROGRESS != link->send_status) { break; }
4694
4695 /* handle message */
4696 ret = isotp_receive_flow_control_frame(link, &message, len);
4697
4698 if (ISOTP_RET_OK == ret) {
4699 /* refresh bs timer */
4700 link->send_timer_bs = isotp_user_get_us() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT_US;
4701
4702 /* overflow */
4703 if (PCI_FLOW_STATUS_OVERFLOW == message.as.flow_control.FS) {
4704 link->send_protocol_result = ISOTP_PROTOCOL_RESULT_BUFFER_OVFLW;
4705 link->send_status = ISOTP_SEND_STATUS_ERROR;
4706 }
4707
4708 /* wait */
4709 else if (PCI_FLOW_STATUS_WAIT == message.as.flow_control.FS) {
4710 link->send_wtf_count += 1;
4711 /* wait exceed allowed count */
4712 if (link->send_wtf_count > ISO_TP_MAX_WFT_NUMBER) {
4713 link->send_protocol_result = ISOTP_PROTOCOL_RESULT_WFT_OVRN;
4714 link->send_status = ISOTP_SEND_STATUS_ERROR;
4715 }
4716 }
4717
4718 /* permit send */
4719 else if (PCI_FLOW_STATUS_CONTINUE == message.as.flow_control.FS) {
4720 if (0 == message.as.flow_control.BS) {
4721 link->send_bs_remain = ISOTP_INVALID_BS;
4722 } else {
4723 link->send_bs_remain = message.as.flow_control.BS;
4724 }
4725 uint32_t message_st_min_us = isotp_st_min_to_us(message.as.flow_control.STmin);
4726 link->send_st_min_us = message_st_min_us > ISO_TP_DEFAULT_ST_MIN_US
4727 ? message_st_min_us
4728 : ISO_TP_DEFAULT_ST_MIN_US; // prefer as much st_min as possible for stability?
4729 link->send_wtf_count = 0;
4730 }
4731 }
4732 break;
4733 default: break;
4734 };
4735
4736#ifdef ISO_TP_RECEIVE_COMPLETE_CALLBACK
4737 /* Notify user via callback if registered */
4738 if (link->receive_status == ISOTP_RECEIVE_STATUS_FULL && link->rx_done_cb != NULL
4739#ifdef ISO_TP_ENABLE_STREAMING
4740 && !link->receive_streaming
4741#endif
4742 ) {
4743 link->rx_done_cb(link, link->receive_buffer, link->receive_size, link->rx_done_cb_arg);
4744 link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
4745 }
4746#endif
4747 return;
4748}
4749
4750int isotp_receive(IsoTpLink* link, uint8_t* payload, const uint32_t payload_size, uint32_t* out_size) {
4751 uint32_t copylen;
4752
4753#ifdef ISO_TP_RECEIVE_COMPLETE_CALLBACK
4754 /* If callback is registered, isotp_receive should not be used */
4755 if (link->rx_done_cb != NULL) { return ISOTP_RET_ERROR; /* Callback mode active, use callback instead */ }
4756#endif
4757
4758#ifdef ISO_TP_ENABLE_STREAMING
4759 if (link->receive_streaming) { return ISOTP_RET_ERROR; }
4760#endif
4761
4762 if (ISOTP_RECEIVE_STATUS_FULL != link->receive_status) { return ISOTP_RET_NO_DATA; }
4763
4764 copylen = link->receive_size;
4765 if (copylen > payload_size) { copylen = payload_size; }
4766
4767 memcpy(payload, link->receive_buffer, copylen);
4768 *out_size = copylen;
4769
4770 link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
4771
4772 return ISOTP_RET_OK;
4773}
4774
4775#ifdef ISO_TP_ENABLE_STREAMING
4776int isotp_receive_streaming(IsoTpLink* link, uint8_t* payload, const uint32_t payload_size, uint32_t* out_size, bool* is_complete) {
4777 uint32_t copylen;
4778
4779 if (link == NULL || payload == NULL || out_size == NULL || is_complete == NULL) { return ISOTP_RET_ERROR; }
4780 if (ISOTP_RECEIVE_STATUS_FULL != link->receive_status) { return ISOTP_RET_NO_DATA; }
4781
4782 copylen = link->receive_streaming ? link->receive_stream_size : link->receive_size;
4783 if (payload_size < copylen) { return ISOTP_RET_NOSPACE; }
4784
4785 (void)memcpy(payload, link->receive_buffer, copylen);
4786 *out_size = copylen;
4787 *is_complete = link->receive_offset >= link->receive_size && link->receive_stream_carry_size == 0;
4788
4789 if (!link->receive_streaming || *is_complete) {
4790 link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
4791 link->receive_streaming = 0;
4792 return ISOTP_RET_OK;
4793 }
4794
4795 link->receive_stream_size = link->receive_stream_carry_size;
4796 if (link->receive_stream_size > link->receive_buf_size) {
4797 link->receive_stream_size = link->receive_buf_size;
4798 }
4799 if (link->receive_stream_size > 0) {
4800 (void)memcpy(link->receive_buffer, link->receive_stream_carry, link->receive_stream_size);
4801 link->receive_stream_carry_size -= (uint8_t)link->receive_stream_size;
4802 if (link->receive_stream_carry_size > 0) {
4803 (void)memmove(link->receive_stream_carry, link->receive_stream_carry + link->receive_stream_size, link->receive_stream_carry_size);
4804 }
4805 }
4806
4807 if (link->receive_stream_carry_size > 0 || link->receive_offset >= link->receive_size) {
4808 link->receive_status = ISOTP_RECEIVE_STATUS_FULL;
4809 } else {
4810 link->receive_status = ISOTP_RECEIVE_STATUS_INPROGRESS;
4811 link->receive_bs_count = 1;
4812 isotp_send_flow_control(link, PCI_FLOW_STATUS_CONTINUE, link->receive_bs_count, ISO_TP_DEFAULT_ST_MIN_US);
4813 link->receive_timer_cr = isotp_user_get_us() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT_US;
4814 }
4815
4816 return ISOTP_RET_OK;
4817}
4818#endif
4819
4820void isotp_init_link(IsoTpLink* link, uint32_t sendid, uint8_t* sendbuf, uint32_t sendbufsize, uint8_t* recvbuf, uint32_t recvbufsize) {
4821 memset(link, 0, sizeof(*link));
4822 link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
4823 link->send_status = ISOTP_SEND_STATUS_IDLE;
4824 link->send_arbitration_id = sendid;
4825 link->send_buffer = sendbuf;
4826 link->send_buf_size = sendbufsize;
4827 link->receive_buffer = recvbuf;
4828 link->receive_buf_size = recvbufsize;
4829 link->tx_dl = ISO_TP_DEFAULT_TX_DL;
4830 link->rx_dl = ISOTP_CAN_DL_CLASSIC;
4831
4832#ifdef ISO_TP_TRANSMIT_COMPLETE_CALLBACK
4833 link->tx_done_cb = NULL;
4834 link->tx_done_cb_arg = NULL;
4835#endif
4836
4837#ifdef ISO_TP_RECEIVE_COMPLETE_CALLBACK
4838 link->rx_done_cb = NULL;
4839 link->rx_done_cb_arg = NULL;
4840#endif
4841
4842 return;
4843}
4844
4845int isotp_set_tx_dl(IsoTpLink* link, uint8_t tx_dl) {
4846 if (link == NULL) {
4847 isotp_user_debug("Link is null!");
4848 return ISOTP_RET_ERROR;
4849 }
4850
4851 if (tx_dl < ISOTP_CAN_DL_CLASSIC || tx_dl > ISO_TP_MAX_CAN_FRAME_SIZE || !isotp_is_valid_can_dl(tx_dl)) {
4852#ifndef ISO_TP_NO_FORMATTED_ERRORS
4853 char message[ISOTP_MAX_ERROR_MSG_SIZE] = {0};
4854 int32_t writtenChars =
4855 ISOTP_SNPRINTF(&message[0], ISOTP_MAX_ERROR_MSG_SIZE, "Invalid TX_DL of %u bytes; must be a CAN frame length between 8 and %u!\n",
4856 (unsigned int)tx_dl, (unsigned int)ISO_TP_MAX_CAN_FRAME_SIZE);
4857
4858 assert(writtenChars <= ISOTP_MAX_ERROR_MSG_SIZE);
4859 (void)writtenChars;
4860
4861 isotp_user_debug(message);
4862#else
4863 isotp_user_debug("Invalid TX_DL; must be a valid CAN frame length.\n");
4864#endif
4865 return ISOTP_RET_ERROR;
4866 }
4867
4868 if (ISOTP_SEND_STATUS_INPROGRESS == link->send_status) {
4869 isotp_user_debug("Cannot change TX_DL while a transmission is in progress.\n");
4870 return ISOTP_RET_INPROGRESS;
4871 }
4872
4873 link->tx_dl = tx_dl;
4874
4875 return ISOTP_RET_OK;
4876}
4877
4878uint8_t isotp_get_tx_dl(const IsoTpLink* link) {
4879 if (link == NULL) {
4880 isotp_user_debug("Link is null!");
4881 return 0;
4882 }
4883
4884 return isotp_tx_dl(link);
4885}
4886
4887void isotp_destroy_link(IsoTpLink* link) {
4888 if (link == NULL) { return; }
4889
4890 // Clear callbacks
4891#ifdef ISO_TP_TRANSMIT_COMPLETE_CALLBACK
4892 link->tx_done_cb = NULL;
4893 link->tx_done_cb_arg = NULL;
4894#endif
4895
4896#ifdef ISO_TP_RECEIVE_COMPLETE_CALLBACK
4897 link->rx_done_cb = NULL;
4898 link->rx_done_cb_arg = NULL;
4899#endif
4900
4901 // Reset link state (optional, but good practice)
4902 memset(link, 0, sizeof(IsoTpLink));
4903}
4904
4905void isotp_poll(IsoTpLink* link) {
4906 int ret;
4907
4908 /* only polling when operation in progress */
4909 if (ISOTP_SEND_STATUS_INPROGRESS == link->send_status) {
4910 /* continue send data */
4911 if (/* send data if bs_remain is invalid or bs_remain large than zero */
4912 (ISOTP_INVALID_BS == link->send_bs_remain || link->send_bs_remain > 0) &&
4913 /* and if st_min is zero or go beyond interval time */
4914 (0 == link->send_st_min_us || IsoTpTimeAfter(isotp_user_get_us(), link->send_timer_st))) {
4915 ret = isotp_send_consecutive_frame(link);
4916 if (ISOTP_RET_OK == ret) {
4917 if (ISOTP_INVALID_BS != link->send_bs_remain) { link->send_bs_remain -= 1; }
4918 link->send_timer_bs = isotp_user_get_us() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT_US;
4919 link->send_timer_st = isotp_user_get_us() + link->send_st_min_us;
4920
4921 /* check if send finish */
4922 if (link->send_offset >= link->send_size) {
4923 link->send_status = ISOTP_SEND_STATUS_IDLE;
4924#ifdef ISO_TP_TRANSMIT_COMPLETE_CALLBACK
4925 if (link->tx_done_cb != NULL) { link->tx_done_cb(link, link->send_size, link->tx_done_cb_arg); }
4926#endif
4927 }
4928 } else if (ISOTP_RET_NOSPACE == ret) {
4929 /* shim reported that it isn't able to send a frame at present, retry on next call */
4930 } else {
4931 link->send_status = ISOTP_SEND_STATUS_ERROR;
4932 }
4933 }
4934
4935 /* check timeout */
4936 if (IsoTpTimeAfter(isotp_user_get_us(), link->send_timer_bs)) {
4937 link->send_protocol_result = ISOTP_PROTOCOL_RESULT_TIMEOUT_BS;
4938 link->send_status = ISOTP_SEND_STATUS_ERROR;
4939 }
4940 }
4941
4942 /* only polling when operation in progress */
4943 if (ISOTP_RECEIVE_STATUS_INPROGRESS == link->receive_status) {
4944 /* check timeout */
4945 if ((link->receive_timer_cr > 0) && IsoTpTimeAfter(isotp_user_get_us(), link->receive_timer_cr)) {
4946 link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_TIMEOUT_CR;
4947 link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
4948 }
4949 }
4950
4951 return;
4952}
4953
4954#ifdef ISO_TP_TRANSMIT_COMPLETE_CALLBACK
4955void isotp_set_tx_done_cb(IsoTpLink* link, isotp_tx_done_cb cb, void* arg) {
4956 if (link != NULL) {
4957 link->tx_done_cb = cb;
4958 link->tx_done_cb_arg = arg;
4959 }
4960}
4961#endif
4962
4963#ifdef ISO_TP_RECEIVE_COMPLETE_CALLBACK
4964void isotp_set_rx_done_cb(IsoTpLink* link, isotp_rx_done_cb cb, void* arg) {
4965 if (link != NULL) {
4966 link->rx_done_cb = cb;
4967 link->rx_done_cb_arg = arg;
4968 }
4969}
4970#endif
4971
4972/// \endcond
4973#endif // if defined(UDS_TP_ISOTP_C)
4974
#define STATE_AWAIT_SEND_COMPLETE
Definition iso14229.c:362
#define STATE_AWAIT_RESPONSE
Definition iso14229.c:363
#define STATE_IDLE
Definition iso14229.c:360
#define STATE_SENDING
Definition iso14229.c:361
#define UDS_LEV_DS_DS
Default Session.
Definition iso14229.h:420
#define UDS_LEV_DS_PRGS
Programming Session.
Definition iso14229.h:421
#define UDS_LEV_DS_EXTDS
Extended Diagnostic Session.
Definition iso14229.h:422
#define UDS_LEV_RCTP_RRR
RequestRoutineResults.
Definition iso14229.h:471
#define UDS_LEV_RCTP_STPR
StopRoutine.
Definition iso14229.h:470
#define UDS_LEV_RCTP_STR
StartRoutine.
Definition iso14229.h:469
#define UDS_LEV_RT_ERPSD
Enable Rapid Power Shut Down.
Definition iso14229.h:435
#define UDS_MOOP_ADDFILE
AddFile.
Definition iso14229.h:480
#define UDS_MOOP_DELFILE
DeleteFile.
Definition iso14229.h:481
#define UDS_MOOP_RDDIR
ReadDirectory.
Definition iso14229.h:484
#define UDS_MOOP_RSFILE
ResumeFile.
Definition iso14229.h:485
#define UDS_MOOP_RDFILE
ReadFile.
Definition iso14229.h:483
#define UDS_MOOP_REPLFILE
ReplaceFile.
Definition iso14229.h:482
UDSErr_t(*) UDSService(UDSServer_t *srv, UDSReq_t *r)
signature of internal service handlers
Definition iso14229.c:2582
ISO 14229 (UDS) library.
#define UDS_CLIENT_DEFAULT_P2_MS
default P2 timeout
Definition iso14229.h:146
UDSErr_t UDSSendECUReset(UDSClient_t *client, uint8_t type)
Request ECUReset.
Definition iso14229.c:667
UDSErr_t UDSServerTpISOTpCInit(UDSTpISOTpC_t *tp, uint32_t source_addr, uint32_t target_addr, uint32_t source_addr_func)
Initialize isotp-c transport for UDSServer_t.
Definition iso14229.c:3318
void UDSServerPoll(UDSServer_t *srv)
Call this at <5ms intervals.
Definition iso14229.c:2790
UDSErr_t UDSClientTpISOTpCSocketCANInit(UDSTpISOTpCSocketCAN_t *tp, const char *ifname, uint32_t source_addr, uint32_t target_addr, uint32_t target_addr_func)
Initialize isotp-c over SocketCAN transport for UDSClient_t.
Definition iso14229.c:3476
UDSErr_t UDSTpRecv(UDSTp_t *hdl, uint8_t *buf, size_t bufsiz, size_t *recvlen, UDSSDU_t *info)
Receive from transport.
Definition iso14229.c:2891
UDSEvent_t
UDS events.
Definition iso14229.h:277
@ UDS_EVT_Custom
Definition iso14229.h:303
@ UDS_EVT_RequestFileTransfer
Definition iso14229.h:300
@ UDS_EVT_ReadDTCInformation
Definition iso14229.h:283
@ UDS_EVT_ClearDiagnosticInfo
Definition iso14229.h:282
@ UDS_EVT_DiagSessCtrl
Definition iso14229.h:280
@ UDS_EVT_DynamicDefineDataId
Definition iso14229.h:291
@ UDS_EVT_SecAccessRequestSeed
Definition iso14229.h:287
@ UDS_EVT_SessionTimeout
Definition iso14229.h:298
@ UDS_EVT_WriteMemByAddr
Definition iso14229.h:290
@ UDS_EVT_SecAccessValidateKey
Definition iso14229.h:288
@ UDS_EVT_TransferData
Definition iso14229.h:296
@ UDS_EVT_RequestDownload
Definition iso14229.h:294
@ UDS_EVT_RoutineCtrl
Definition iso14229.h:293
@ UDS_EVT_Poll
Definition iso14229.h:305
@ UDS_EVT_WriteDataByIdent
Definition iso14229.h:289
@ UDS_EVT_RequestTransferExit
Definition iso14229.h:297
@ UDS_EVT_ReadMemByAddr
Definition iso14229.h:285
@ UDS_EVT_CommCtrl
Definition iso14229.h:286
@ UDS_EVT_ResponseReceived
Definition iso14229.h:307
@ UDS_EVT_SendComplete
Definition iso14229.h:306
@ UDS_EVT_Idle
Definition iso14229.h:308
@ UDS_EVT_RequestUpload
Definition iso14229.h:295
@ UDS_EVT_LinkControl
Definition iso14229.h:302
@ UDS_EVT_ControlDTCSetting
Definition iso14229.h:301
@ UDS_EVT_IOControl
Definition iso14229.h:292
@ UDS_EVT_EcuReset
Definition iso14229.h:281
@ UDS_EVT_DoScheduledReset
Definition iso14229.h:299
@ UDS_EVT_Err
Definition iso14229.h:278
@ UDS_EVT_MAX
Definition iso14229.h:310
@ UDS_EVT_ReadDataByIdent
Definition iso14229.h:284
UDSErr_t UDSSendTesterPresent(UDSClient_t *client)
What's up?
Definition iso14229.c:701
#define UDS_SERVER_DEFAULT_P2_MS
default P2 duration
Definition iso14229.h:156
#define UDS_CLIENT_DEFAULT_P2_STAR_MS
default P2* timeout
Definition iso14229.h:150
UDSErr_t UDSSendRequestTransferExit(UDSClient_t *client)
Call this when finished with TransferData.
Definition iso14229.c:907
UDSErr_t UDSTpPoll(UDSTp_t *hdl)
call this at <5ms intervals
Definition iso14229.c:2899
UDSErr_t UDSSendRequestDownload(UDSClient_t *client, uint8_t dataFormatIdentifier, uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress, size_t memorySize)
Request to Download via TransferData.
Definition iso14229.c:804
UDSErr_t UDSUnpackSecurityAccessResponse(const UDSClient_t *client, struct SecurityAccessResponse *resp)
Parse server's response to SecurityAccess.
Definition iso14229.c:1099
#define UDS_TP_NOOP_ADDR
flags A_SA / A_TA as unused
Definition iso14229.h:555
UDSErr_t UDSServerTpIsoTpSockInit(UDSTpIsoTpSock_t *tp, const char *ifname, uint32_t source_addr, uint32_t target_addr, uint32_t source_addr_func)
for UDSServer_t
Definition iso14229.c:3717
UDSErr_t UDSSendWDBI(UDSClient_t *client, uint16_t dataIdentifier, const uint8_t *data, uint16_t size)
Write Data By Identifier.
Definition iso14229.c:736
UDSErr_t UDSSendCommCtrl(UDSClient_t *client, uint8_t ctrl, uint8_t comm)
Change communication settings.
Definition iso14229.c:689
#define UDS_TP_MTU
ISOTP is the only supported tp type, so UDS inherits its MTU.
Definition iso14229.h:118
UDSErr_t UDSSendRequestUpload(UDSClient_t *client, uint8_t dataFormatIdentifier, uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress, size_t memorySize)
Request to Upload via TransferData.
Definition iso14229.c:841
uint32_t UDSMillis(void)
Get time in milliseconds.
#define UDS_SERVER_0x27_BRUTE_FORCE_MITIGATION_BOOT_DELAY_MS
Amount of time to wait after boot before accepting 0x27 requests.
Definition iso14229.h:186
UDSErr_t UDSUnpackRDBIResponse(UDSClient_t *client, UDSRDBIVar_t *vars, uint16_t numVars)
Parse server's response to RDBI.
Definition iso14229.c:1191
#define UDS_SERVER_DEFAULT_S3_MS
default S3 duration (ISO14229-2 2013 Table 5: 5000 -0/+200 ms)
Definition iso14229.h:164
UDSErr_t UDSUnpackRoutineControlResponse(const UDSClient_t *client, struct RoutineControlResponse *resp)
Parse server's response to RoutineControl.
Definition iso14229.c:1124
UDSErr_t UDSSendSecurityAccess(UDSClient_t *client, uint8_t level, const uint8_t *data, uint16_t size)
Get Security Access.
Definition iso14229.c:1062
unsigned int UDS_LogLevel_t
one of valid values for UDS_LOG_LEVEL
Definition iso14229.h:664
#define UDS_SERVER_DEFAULT_P2_STAR_MS
default P2* duration
Definition iso14229.h:160
UDSErr_t UDSClientTpIsoTpSockInit(UDSTpIsoTpSock_t *tp, const char *ifname, uint32_t source_addr, uint32_t target_addr, uint32_t target_addr_func)
for UDSClient_t
Definition iso14229.c:3744
UDSErr_t UDSSendTransferData(UDSClient_t *client, uint8_t blockSequenceCounter, uint16_t blockLength, const uint8_t *data, uint16_t size)
Transfer Data to/from a buffer.
Definition iso14229.c:876
uint8_t UDS_A_TA_Type_t
private: oneof Uds_a_ta_type
Definition iso14229.h:539
UDSErr_t UDSSendRequestFileTransfer(UDSClient_t *client, uint8_t mode, const char *filePath, size_t filePathLen, size_t fileSizeUncompressed, size_t fileSizeCompressed)
filesystem-based frontend to TransferData
Definition iso14229.c:917
UDSErr_t UDSSendRoutineCtrl(UDSClient_t *client, uint8_t type, uint16_t routineIdentifier, const uint8_t *data, uint16_t size)
Request to Twiddle Routines.
Definition iso14229.c:768
UDSErr_t UDSClientTpISOTpCInit(UDSTpISOTpC_t *tp, uint32_t source_addr, uint32_t target_addr, uint32_t target_addr_func)
Initialize isotp-c transport for UDSClient_t.
Definition iso14229.c:3323
UDSErr_t
Error Codes, including NRCs defined by the standard.
Definition iso14229.h:317
void UDSTpISOTpCSocketCANDeinit(UDSTpISOTpCSocketCAN_t *tp)
release socket
Definition iso14229.c:3483
#define UDS_ISOTP_MTU
ISO-TP Maximum Transmission Unit (ISO-15764-2-2004 section 5.3.3).
Definition iso14229.h:114
UDSErr_t UDSUnpackRequestDownloadResponse(const UDSClient_t *client, struct RequestDownloadResponse *resp)
Parse server's response to RequestDownload.
Definition iso14229.c:1151
UDSErr_t UDSCtrlDTCSetting(UDSClient_t *client, uint8_t dtcSettingType, const uint8_t *dtcSettingControlOptionRecord, uint16_t len)
control DTC setting
Definition iso14229.c:1022
UDSErr_t UDSClientInit(UDSClient_t *client)
Call this once.
Definition iso14229.c:366
#define UDS_SERVER_DEFAULT_XFER_DATA_MAX_BLOCKLENGTH
Definition iso14229.h:198
#define UDS_SERVER_0x27_BRUTE_FORCE_MITIGATION_AUTH_FAIL_DELAY_MS
Amount of time to wait after an authentication failure before accepting another 0x27 request.
Definition iso14229.h:191
UDSErr_t UDSTpSend(UDSTp_t *hdl, const uint8_t *buf, size_t len, const UDSSDU_t *info)
Send to transport.
Definition iso14229.c:2884
UDSErr_t UDSServerTpISOTpCSocketCANInit(UDSTpISOTpCSocketCAN_t *tp, const char *ifname, uint32_t source_addr, uint32_t target_addr, uint32_t source_addr_func)
Initialize isotp-c over SocketCAN transport for UDSServer_t.
Definition iso14229.c:3469
UDSErr_t UDSSendDiagSessCtrl(UDSClient_t *client, uint8_t mode)
Change the diagnostic session.
Definition iso14229.c:678
#define UDS_ASSERT(x)
used to enforce runtime invariants within iso14229
Definition iso14229.h:622
UDSErr_t UDSClientPoll(UDSClient_t *client)
Call at <5ms intervals.
Definition iso14229.c:1173
UDSErr_t UDSSendBytes(UDSClient_t *client, const uint8_t *data, uint16_t size)
Send user-defined bytes to a UDS server.
Definition iso14229.c:654
UDSErr_t UDSSendRDBI(UDSClient_t *client, const uint16_t *didList, uint16_t numDataIdentifiers)
Read Data By Identifier.
Definition iso14229.c:712
UDSErr_t UDSServerInit(UDSServer_t *srv)
call this once
Definition iso14229.c:2773
void UDSTpIsoTpSockDeinit(const UDSTpIsoTpSock_t *tp)
release sockets
Definition iso14229.c:3770
#define UDS_SERVER_DEFAULT_POWER_DOWN_TIME_MS
Definition iso14229.h:177
Request download response structure.
Definition iso14229.h:789
Routine control response structure.
Definition iso14229.h:796
const uint8_t * routineStatusRecord
Definition iso14229.h:799
size_t routineStatusRecordLength
Definition iso14229.h:800
uint16_t routineIdentifier
Definition iso14229.h:798
Security access response structure.
Definition iso14229.h:780
const uint8_t * securitySeed
Definition iso14229.h:782
Clear diagnostic information arguments.
Definition iso14229.h:960
UDS client structure.
Definition iso14229.h:753
uint8_t cfg_file_size_parameter_length
Definition iso14229.h:763
uint8_t cfg_data_format_identifier
Definition iso14229.h:762
uint16_t p2_ms
Definition iso14229.h:766
unsigned cfg_ignore_srv_sess_timing
Definition iso14229.h:761
int(*) fn(struct UDSClient *client, UDSEvent_t evt, void *ev_data)
Definition iso14229.h:756
unsigned cfg_suppress_pos_resp
Definition iso14229.h:758
uint32_t p2_timer
Definition iso14229.h:768
size_t send_size
Definition iso14229.h:772
size_t recv_size
Definition iso14229.h:771
uint8_t send_buf[UDS_CLIENT_SEND_BUF_SIZE]
Definition iso14229.h:774
uint8_t state
Definition iso14229.h:769
uint32_t p2_star_ms
Definition iso14229.h:767
unsigned cfg_send_functional
Definition iso14229.h:759
uint8_t recv_buf[UDS_CLIENT_RECV_BUF_SIZE]
Definition iso14229.h:773
UDSTp_t * tp
Definition iso14229.h:755
Communication control arguments.
Definition iso14229.h:1061
Control DTC setting arguments.
Definition iso14229.h:1227
Custom service arguments.
Definition iso14229.h:1247
Dynamically define data identifier arguments.
Definition iso14229.h:1108
union UDSDDDIArgs_t::@052263275324350175074117356122047100356070003133 subFuncArgs
Diagnostic session control arguments.
Definition iso14229.h:942
ECU reset arguments.
Definition iso14229.h:951
uint32_t powerDownTimeMillis
Definition iso14229.h:953
Input/output control by identifier arguments.
Definition iso14229.h:1132
Link control arguments.
Definition iso14229.h:1236
Read data by identifier arguments.
Definition iso14229.h:1042
Read data by identifier variable structure.
Definition iso14229.h:806
uint16_t len
Definition iso14229.h:808
void *(*) UnpackFn(void *dst, const void *src, size_t n)
Definition iso14229.h:810
Read DTC information arguments.
Definition iso14229.h:969
union UDSRDTCIArgs_t::@242172112264143020077310143126066111376236317004 subFuncArgs
Read memory by address arguments.
Definition iso14229.h:1051
Server request context.
Definition iso14229.h:875
uint8_t send_buf[UDS_SERVER_SEND_BUF_SIZE]
Definition iso14229.h:877
size_t send_len
Definition iso14229.h:879
uint8_t recv_buf[UDS_SERVER_RECV_BUF_SIZE]
Definition iso14229.h:876
size_t recv_len
Definition iso14229.h:878
UDSSDU_t info
Definition iso14229.h:881
Request download arguments.
Definition iso14229.h:1156
uint16_t maxNumberOfBlockLength
Definition iso14229.h:1160
Request file transfer arguments.
Definition iso14229.h:1200
Request transfer exit arguments.
Definition iso14229.h:1190
Request upload arguments.
Definition iso14229.h:1167
uint16_t maxNumberOfBlockLength
Definition iso14229.h:1171
Routine control arguments.
Definition iso14229.h:1144
Service data unit (SDU).
Definition iso14229.h:546
uint32_t A_SA
Definition iso14229.h:549
uint32_t A_TA
Definition iso14229.h:550
UDS_A_TA_Type_t A_TA_Type
Definition iso14229.h:551
Security access request seed arguments.
Definition iso14229.h:1070
Security access validate key arguments.
Definition iso14229.h:1081
UDS server structure.
Definition iso14229.h:887
size_t xferTotalBytes
Definition iso14229.h:915
uint32_t sec_access_auth_fail_timer
Definition iso14229.h:903
uint16_t p2_ms
Server time constants (milliseconds).
Definition iso14229.h:895
uint32_t p2_star_ms
Definition iso14229.h:896
bool notReadyToReceive
UDS-1 2013 defines the following conditions under which the server does not process incoming requests...
Definition iso14229.h:934
uint8_t securityLevel
Definition iso14229.h:920
uint32_t sec_access_boot_delay_timer
Definition iso14229.h:904
uint16_t s3_ms
Definition iso14229.h:897
UDSReq_t r
Definition iso14229.h:936
UDSTp_t * tp
Definition iso14229.h:888
size_t xferBlockLength
Definition iso14229.h:917
UDSErr_t(*) fn(struct UDSServer *srv, UDSEvent_t event, void *arg)
Definition iso14229.h:889
uint32_t s3_session_timeout_timer
Definition iso14229.h:902
size_t xferByteCounter
Definition iso14229.h:916
uint8_t ecuResetScheduled
Definition iso14229.h:899
uint8_t xferBlockSequenceCounter
Definition iso14229.h:913
uint32_t p2_timer
Definition iso14229.h:901
uint8_t sessionType
Definition iso14229.h:919
bool xferIsActive
UDS-1-2013: Table 407 - 0x36 TransferData Supported negative response codes requires that the server ...
Definition iso14229.h:912
bool requestInProgress
Definition iso14229.h:923
uint32_t ecuResetTimer
Definition iso14229.h:900
isotp-c over SocketCAN implementation of UDSTp_t
Definition iso14229.h:2321
isotp-c implementation of UDSTp_t
Definition iso14229.h:2263
linux ISO-TP socket implementation of UDSTp_t
Definition iso14229.h:2369
UDS Transport layer.
Definition iso14229.h:561
UDSErr_t(*) poll(struct UDSTp *hdl)
Poll the transport layer.
Definition iso14229.h:591
UDSErr_t(*) recv(struct UDSTp *hdl, uint8_t *buf, size_t bufsiz, size_t *recvlen, UDSSDU_t *info)
Receive data from the transport.
Definition iso14229.h:583
UDSErr_t(*) send(struct UDSTp *hdl, const uint8_t *buf, const size_t len, const UDSSDU_t *info)
Send data to the transport.
Definition iso14229.h:571
Transfer data arguments.
Definition iso14229.h:1178
Write data by identifier arguments.
Definition iso14229.h:1090
Write memory by address arguments.
Definition iso14229.h:1099