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