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