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 return NegativeResponse(r, UDS_NRC_ConditionsNotCorrect);
1999 }
2000 if (r->recv_len < UDS_0X38_REQ_BASE_LEN) {
2001 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
2002 }
2003
2004 uint8_t mode_of_operation = r->recv_buf[1];
2005 if (mode_of_operation < UDS_MOOP_ADDFILE || mode_of_operation > UDS_MOOP_RDFILE) {
2006 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
2007 }
2008 uint16_t file_path_len = (uint16_t)(((uint16_t)r->recv_buf[2] << 8) + (uint16_t)r->recv_buf[3]);
2009 uint8_t data_format_identifier = 0;
2010 uint8_t file_size_parameter_length = 0;
2011 size_t file_size_uncompressed = 0;
2012 size_t file_size_compressed = 0;
2013 uint16_t byte_idx = 4 + file_path_len;
2014
2015 if (byte_idx > r->recv_len) {
2016 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
2017 }
2018
2019 if ((mode_of_operation == UDS_MOOP_DELFILE) || (mode_of_operation == UDS_MOOP_RDDIR)) {
2020 // ISO14229:2020 Table 481:
2021 // If the modeOfOperation parameter equals to 0x02 (DeleteFile) and 0x05 (ReadDir) this
2022 // parameter [dataFormatIdentifier] shall not be included in the request message.
2023 } else {
2024 data_format_identifier = r->recv_buf[byte_idx];
2025 byte_idx++;
2026 }
2027
2028 if ((mode_of_operation == UDS_MOOP_DELFILE) || (mode_of_operation == UDS_MOOP_RDFILE) ||
2029 (mode_of_operation == UDS_MOOP_RDDIR)) {
2030 // ISO14229:2020 Table 481:
2031 // If the modeOfOperation parameter equals to 0x02 (DeleteFile), 0x04 (ReadFile) or 0x05
2032 // (ReadDir) this parameter [fileSizeParameterLength] shall not be included in the request
2033 // message. If the modeOfOperation parameter equals to 0x02 (DeleteFile), 0x04 (ReadFile) or
2034 // 0x05 (ReadDir) this parameter [fileSizeUncompressed] shall not be included in the request
2035 // message. If the modeOfOperation parameter equals to 0x02 (DeleteFile), 0x04 (ReadFile) or
2036 // 0x05 (ReadDir) this parameter [fileSizeCompressed] shall not be included in the request
2037 // message.
2038 } else {
2039 file_size_parameter_length = r->recv_buf[byte_idx];
2040 byte_idx++;
2041
2042 static_assert(sizeof(file_size_uncompressed) == sizeof(file_size_compressed),
2043 "Both should be k-byte numbers per Table 480");
2044 if (file_size_parameter_length > sizeof(file_size_compressed)) {
2045 return NegativeResponse(r, UDS_NRC_RequestOutOfRange);
2046 }
2047 if (byte_idx + 2 * file_size_uncompressed > r->recv_len) {
2048 return NegativeResponse(r, UDS_NRC_RequestOutOfRange);
2049 }
2050 for (size_t i = 0; i < file_size_parameter_length; i++) {
2051 uint8_t data_byte = r->recv_buf[byte_idx];
2052 uint8_t shift_by_bytes = (uint8_t)(file_size_parameter_length - i - 1);
2053 file_size_uncompressed |= (size_t)data_byte << (8 * shift_by_bytes);
2054 byte_idx++;
2055 }
2056 for (size_t i = 0; i < file_size_parameter_length; i++) {
2057 uint8_t data_byte = r->recv_buf[byte_idx];
2058 uint8_t shift_by_bytes = (uint8_t)(file_size_parameter_length - i - 1);
2059 file_size_compressed |= (size_t)data_byte << (8 * shift_by_bytes);
2060 byte_idx++;
2061 }
2062 }
2063
2065 .modeOfOperation = mode_of_operation,
2066 .filePathLen = file_path_len,
2067 .filePath = &r->recv_buf[4],
2068 .dataFormatIdentifier = data_format_identifier,
2069 .fileSizeUnCompressed = file_size_uncompressed,
2070 .fileSizeCompressed = file_size_compressed,
2071 };
2072
2073 err = EmitEvent(srv, UDS_EVT_RequestFileTransfer, &args);
2074
2075 if (UDS_PositiveResponse != err) {
2076 return NegativeResponse(r, err);
2077 }
2078
2079 ResetTransfer(srv);
2080 srv->xferIsActive = true;
2083
2084 if (args.maxNumberOfBlockLength > UDS_TP_MTU) {
2085 args.maxNumberOfBlockLength = UDS_TP_MTU;
2086 }
2087
2088 r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_REQUEST_FILE_TRANSFER);
2089 r->send_buf[1] = args.modeOfOperation;
2090 r->send_buf[2] = (uint8_t)sizeof(args.maxNumberOfBlockLength);
2091 for (uint8_t idx = 0; idx < (uint8_t)sizeof(args.maxNumberOfBlockLength); idx++) {
2092 uint8_t shiftBytes = (uint8_t)(sizeof(args.maxNumberOfBlockLength) - 1 - idx);
2093 uint8_t byte = (uint8_t)(args.maxNumberOfBlockLength >> (shiftBytes * 8));
2094 r->send_buf[UDS_0X38_RESP_BASE_LEN + idx] = byte;
2095 }
2096 r->send_buf[UDS_0X38_RESP_BASE_LEN + (size_t)sizeof(args.maxNumberOfBlockLength)] =
2098
2099 r->send_len = UDS_0X38_RESP_BASE_LEN + (size_t)sizeof(args.maxNumberOfBlockLength) + 1;
2100 return UDS_PositiveResponse;
2101}
2102
2103static UDSErr_t Handle_0x3D_WriteMemoryByAddress(UDSServer_t *srv, UDSReq_t *r) {
2104 UDSErr_t ret = UDS_PositiveResponse;
2105 void *address = 0;
2106 size_t length = 0;
2107
2108 if (r->recv_len < UDS_0X3D_REQ_MIN_LEN) {
2109 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
2110 }
2111
2112 ret = decodeAddressAndLength(r, &r->recv_buf[1], &address, &length);
2113 if (UDS_PositiveResponse != ret) {
2114 return NegativeResponse(r, ret);
2115 }
2116
2117 uint8_t memorySizeLength = (r->recv_buf[1] & 0xF0) >> 4;
2118 uint8_t memoryAddressLength = r->recv_buf[1] & 0x0F;
2119
2120 uint8_t dataOffset = 2 + memorySizeLength + memoryAddressLength;
2121
2122 if (dataOffset + length != r->recv_len) {
2123 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
2124 }
2125
2127 .memAddr = address,
2128 .memSize = length,
2129 .data = &r->recv_buf[dataOffset],
2130 };
2131
2132 ret = EmitEvent(srv, UDS_EVT_WriteMemByAddr, &args);
2133 if (UDS_PositiveResponse != ret) {
2134 return NegativeResponse(r, ret);
2135 }
2136
2137 r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_WRITE_MEMORY_BY_ADDRESS);
2138 // echo addressAndLengthFormatIdentifier, memoryAddress, and memorySize
2139 memcpy(&r->send_buf[1], &r->recv_buf[1], 1 + memorySizeLength + memoryAddressLength);
2140 r->send_len = UDS_0X3D_RESP_BASE_LEN + memorySizeLength + memoryAddressLength;
2141 return UDS_PositiveResponse;
2142}
2143
2144static UDSErr_t Handle_0x3E_TesterPresent(UDSServer_t *srv, UDSReq_t *r) {
2145 if ((r->recv_len < UDS_0X3E_REQ_MIN_LEN) || (r->recv_len > UDS_0X3E_REQ_MAX_LEN)) {
2146 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
2147 }
2148 uint8_t zeroSubFunction = r->recv_buf[1];
2149
2150 switch (zeroSubFunction) {
2151 case 0x00:
2152 case 0x80:
2154 r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_TESTER_PRESENT);
2155 r->send_buf[1] = 0x00;
2156 r->send_len = UDS_0X3E_RESP_LEN;
2157 return UDS_PositiveResponse;
2158 default:
2159 return NegativeResponse(r, UDS_NRC_SubFunctionNotSupported);
2160 }
2161}
2162
2163static UDSErr_t Handle_0x85_ControlDTCSetting(UDSServer_t *srv, UDSReq_t *r) {
2164 (void)srv;
2165 if (r->recv_len < UDS_0X85_REQ_BASE_LEN) {
2166 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
2167 }
2168
2169 uint8_t type = r->recv_buf[1] & 0x7F;
2170
2172 .type = type,
2173 .data = r->recv_len > UDS_0X85_REQ_BASE_LEN ? &r->recv_buf[UDS_0X85_REQ_BASE_LEN] : NULL,
2174 .len = r->recv_len > UDS_0X85_REQ_BASE_LEN ? r->recv_len - UDS_0X85_REQ_BASE_LEN : 0,
2175 };
2176
2177 int ret = EmitEvent(srv, UDS_EVT_ControlDTCSetting, &args);
2178 if (UDS_PositiveResponse != ret) {
2179 return NegativeResponse(r, ret);
2180 }
2181
2182 r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_CONTROL_DTC_SETTING);
2183 r->send_buf[1] = type;
2184 r->send_len = UDS_0X85_RESP_LEN;
2185 return UDS_PositiveResponse;
2186}
2187
2188static UDSErr_t Handle_0x87_LinkControl(UDSServer_t *srv, UDSReq_t *r) {
2189 if (r->recv_len < UDS_0X85_REQ_BASE_LEN) {
2190 return NegativeResponse(r, UDS_NRC_IncorrectMessageLengthOrInvalidFormat);
2191 }
2192
2193 uint8_t type = r->recv_buf[1] & 0x7F;
2194
2195 if (type == 0x03 && (r->recv_buf[1] & 0x80) == 0 &&
2196 r->info.A_TA_Type == UDS_A_TA_TYPE_FUNCTIONAL) {
2197 UDS_LOGW(__FILE__, "0x87 LinkControl: Transitioning mode without suppressing response!");
2198 }
2199
2200 r->send_buf[0] = UDS_RESPONSE_SID_OF(kSID_LINK_CONTROL);
2201 r->send_buf[1] = r->recv_buf[1]; /* do not use `type` because we want to preserve the suppress
2202 response bit */
2203 r->send_len = UDS_0X87_RESP_LEN;
2204
2205 UDSLinkCtrlArgs_t args = {
2206 .type = type,
2207 .len = (r->recv_len - UDS_0X87_REQ_BASE_LEN),
2208 .data = &r->recv_buf[UDS_0X87_REQ_BASE_LEN],
2209 };
2210
2211 int ret = EmitEvent(srv, UDS_EVT_LinkControl, &args);
2212 if (ret != UDS_PositiveResponse) {
2213 return NegativeResponse(r, ret);
2214 }
2215
2216 return UDS_PositiveResponse;
2217}
2218
2219typedef UDSErr_t (*UDSService)(UDSServer_t *srv, UDSReq_t *r);
2220
2221/**
2222 * @brief Get the internal service handler matching the given SID.
2223 * @param sid
2224 * @return pointer to UDSService or NULL if no match
2225 */
2226static UDSService getServiceForSID(uint8_t sid) {
2227 switch (sid) {
2228 case kSID_DIAGNOSTIC_SESSION_CONTROL:
2229 return &Handle_0x10_DiagnosticSessionControl;
2230 case kSID_ECU_RESET:
2231 return &Handle_0x11_ECUReset;
2232 case kSID_CLEAR_DIAGNOSTIC_INFORMATION:
2233 return &Handle_0x14_ClearDiagnosticInformation;
2234 case kSID_READ_DTC_INFORMATION:
2235 return Handle_0x19_ReadDTCInformation;
2236 case kSID_READ_DATA_BY_IDENTIFIER:
2237 return &Handle_0x22_ReadDataByIdentifier;
2238 case kSID_READ_MEMORY_BY_ADDRESS:
2239 return &Handle_0x23_ReadMemoryByAddress;
2240 case kSID_READ_SCALING_DATA_BY_IDENTIFIER:
2241 return NULL;
2242 case kSID_SECURITY_ACCESS:
2243 return &Handle_0x27_SecurityAccess;
2244 case kSID_COMMUNICATION_CONTROL:
2245 return &Handle_0x28_CommunicationControl;
2246 case kSID_READ_PERIODIC_DATA_BY_IDENTIFIER:
2247 return NULL;
2248 case kSID_DYNAMICALLY_DEFINE_DATA_IDENTIFIER:
2249 return &Handle_0x2C_DynamicDefineDataIdentifier;
2250 case kSID_WRITE_DATA_BY_IDENTIFIER:
2251 return &Handle_0x2E_WriteDataByIdentifier;
2252 case kSID_IO_CONTROL_BY_IDENTIFIER:
2253 return &Handle_0x2F_IOControlByIdentifier;
2254 case kSID_ROUTINE_CONTROL:
2255 return &Handle_0x31_RoutineControl;
2256 case kSID_REQUEST_DOWNLOAD:
2257 return &Handle_0x34_RequestDownload;
2258 case kSID_REQUEST_UPLOAD:
2259 return &Handle_0x35_RequestUpload;
2260 case kSID_TRANSFER_DATA:
2261 return &Handle_0x36_TransferData;
2262 case kSID_REQUEST_TRANSFER_EXIT:
2263 return &Handle_0x37_RequestTransferExit;
2264 case kSID_REQUEST_FILE_TRANSFER:
2265 return &Handle_0x38_RequestFileTransfer;
2266 case kSID_WRITE_MEMORY_BY_ADDRESS:
2267 return &Handle_0x3D_WriteMemoryByAddress;
2268 case kSID_TESTER_PRESENT:
2269 return &Handle_0x3E_TesterPresent;
2270 case kSID_ACCESS_TIMING_PARAMETER:
2271 return NULL;
2272 case kSID_SECURED_DATA_TRANSMISSION:
2273 return NULL;
2274 case kSID_CONTROL_DTC_SETTING:
2275 return &Handle_0x85_ControlDTCSetting;
2276 case kSID_RESPONSE_ON_EVENT:
2277 return NULL;
2278 case kSID_LINK_CONTROL:
2279 return &Handle_0x87_LinkControl;
2280 default:
2281 UDS_LOGI(__FILE__, "no handler for request SID %x", sid);
2282 return NULL;
2283 }
2284}
2285
2286/**
2287 * @brief Call the service if it exists, modifying the response if the spec calls for it.
2288 * @note see UDS-1 2013 7.5.5 Pseudo code example of server response behavior
2289 *
2290 * @param srv
2291 * @param addressingScheme
2292 */
2293static UDSErr_t evaluateServiceResponse(UDSServer_t *srv, UDSReq_t *r) {
2294 UDSErr_t response = UDS_PositiveResponse;
2295 bool suppressResponse = false;
2296 uint8_t sid = r->recv_buf[0];
2297 UDSService service = getServiceForSID(sid);
2298
2299 if (NULL == srv->fn)
2300 return NegativeResponse(r, UDS_NRC_ServiceNotSupported);
2301 UDS_ASSERT(srv->fn); // service handler functions will call srv->fn. it must be valid
2302
2303 switch (sid) {
2304 /* CASE Service_with_sub-function */
2305 /* test if service with sub-function is supported */
2306 case kSID_DIAGNOSTIC_SESSION_CONTROL:
2307 case kSID_ECU_RESET:
2308 case kSID_SECURITY_ACCESS:
2309 case kSID_COMMUNICATION_CONTROL:
2310 case kSID_ROUTINE_CONTROL:
2311 case kSID_TESTER_PRESENT:
2312 case kSID_CONTROL_DTC_SETTING:
2313 case kSID_LINK_CONTROL: {
2314 UDS_ASSERT(service);
2315 response = service(srv, r);
2316
2317 bool suppressPosRspMsgIndicationBit = r->recv_buf[1] & 0x80;
2318
2319 /* test if positive response is required and if responseCode is positive 0x00 */
2320 if (suppressPosRspMsgIndicationBit && (response == UDS_PositiveResponse) &&
2321
2322 // TODO: *not yet a NRC 0x78 response sent*
2323 true) {
2324 suppressResponse = true;
2325 } else {
2326 suppressResponse = false;
2327 }
2328 break;
2329 }
2330
2331 /* CASE Service_without_sub-function */
2332 /* test if service without sub-function is supported */
2333 case kSID_READ_DATA_BY_IDENTIFIER:
2334 case kSID_READ_MEMORY_BY_ADDRESS:
2335 case kSID_WRITE_DATA_BY_IDENTIFIER:
2336 case kSID_REQUEST_DOWNLOAD:
2337 case kSID_REQUEST_UPLOAD:
2338 case kSID_TRANSFER_DATA:
2339 case kSID_REQUEST_FILE_TRANSFER:
2340 case kSID_REQUEST_TRANSFER_EXIT: {
2341 UDS_ASSERT(service);
2342 response = service(srv, r);
2343 break;
2344 }
2345
2346 /* CASE Service_optional */
2347 case kSID_CLEAR_DIAGNOSTIC_INFORMATION:
2348 case kSID_READ_DTC_INFORMATION:
2349 case kSID_READ_SCALING_DATA_BY_IDENTIFIER:
2350 case kSID_READ_PERIODIC_DATA_BY_IDENTIFIER:
2351 case kSID_DYNAMICALLY_DEFINE_DATA_IDENTIFIER:
2352 case kSID_IO_CONTROL_BY_IDENTIFIER:
2353 case kSID_WRITE_MEMORY_BY_ADDRESS:
2354 case kSID_ACCESS_TIMING_PARAMETER:
2355 case kSID_SECURED_DATA_TRANSMISSION:
2356 case kSID_RESPONSE_ON_EVENT:
2357 default: {
2358 if (service) {
2359 response = service(srv, r);
2360 } else { /* getServiceForSID(sid) returned NULL*/
2361 UDSCustomArgs_t args = {
2362 .sid = sid,
2363 .optionRecord = &r->recv_buf[1],
2364 .len = (uint16_t)(r->recv_len - 1),
2365 .copyResponse = safe_copy,
2366 };
2367
2368 r->send_buf[0] = UDS_RESPONSE_SID_OF(sid);
2369 r->send_len = 1;
2370
2371 response = EmitEvent(srv, UDS_EVT_Custom, &args);
2372 if (UDS_PositiveResponse != response)
2373 return NegativeResponse(r, response);
2374 }
2375 break;
2376 }
2377 }
2378
2379 if ((UDS_A_TA_TYPE_FUNCTIONAL == r->info.A_TA_Type) &&
2380 ((UDS_NRC_ServiceNotSupported == response) ||
2381 (UDS_NRC_SubFunctionNotSupported == response) ||
2382 (UDS_NRC_ServiceNotSupportedInActiveSession == response) ||
2383 (UDS_NRC_SubFunctionNotSupportedInActiveSession == response) ||
2384 (UDS_NRC_RequestOutOfRange == response)) &&
2385
2386 // TODO: *not yet a NRC 0x78 response sent*
2387 true) {
2388 /* Suppress negative response message */
2389 suppressResponse = true;
2390 }
2391
2392 if (suppressResponse) {
2393 NoResponse(r);
2394 } else { /* send negative or positive response */
2395 }
2396
2397 return response;
2398}
2399
2400// ========================================================================
2401// Public Functions
2402// ========================================================================
2403
2404UDSErr_t UDSServerInit(UDSServer_t *srv) {
2405 if (NULL == srv) {
2406 return UDS_ERR_INVALID_ARG;
2407 }
2408 memset(srv, 0, sizeof(UDSServer_t));
2409 srv->p2_ms = UDS_SERVER_DEFAULT_P2_MS;
2410 srv->p2_star_ms = UDS_SERVER_DEFAULT_P2_STAR_MS;
2411 srv->s3_ms = UDS_SERVER_DEFAULT_S3_MS;
2412 srv->sessionType = UDS_LEV_DS_DS;
2413 srv->p2_timer = UDSMillis() + srv->p2_ms;
2416 UDSMillis() + UDS_SERVER_0x27_BRUTE_FORCE_MITIGATION_BOOT_DELAY_MS;
2418 return UDS_OK;
2419}
2420
2421void UDSServerPoll(UDSServer_t *srv) {
2422 // UDS-1-2013 Figure 38: Session Timeout (S3)
2423 if (UDS_LEV_DS_DS != srv->sessionType &&
2424 UDSTimeAfter(UDSMillis(), srv->s3_session_timeout_timer)) {
2425 EmitEvent(srv, UDS_EVT_SessionTimeout, NULL);
2426 srv->sessionType = UDS_LEV_DS_DS;
2427 srv->securityLevel = 0;
2428 }
2429
2430 if (srv->ecuResetScheduled && UDSTimeAfter(UDSMillis(), srv->ecuResetTimer)) {
2431 EmitEvent(srv, UDS_EVT_DoScheduledReset, &srv->ecuResetScheduled);
2432 }
2433
2434 UDSTpPoll(srv->tp);
2435
2436 UDSReq_t *r = &srv->r;
2437
2438 if (srv->requestInProgress) {
2439 if (srv->RCRRP) {
2440 // responds only if
2441 // 1. changed (no longer RCRRP), or
2442 // 2. p2_timer has elapsed
2443 UDSErr_t response = evaluateServiceResponse(srv, r);
2444 if (UDS_NRC_RequestCorrectlyReceived_ResponsePending == response) {
2445 // it's the second time the service has responded with RCRRP
2446 srv->notReadyToReceive = true;
2447 } else {
2448 // No longer RCRRP'ing
2449 srv->RCRRP = false;
2450 srv->notReadyToReceive = false;
2451
2452 // Not a consecutive 0x78 response, use p2 instead of p2_star * 0.3
2453 srv->p2_timer = UDSMillis() + srv->p2_ms;
2454 }
2455 }
2456
2457 if (UDSTimeAfter(UDSMillis(), srv->p2_timer)) {
2458 ssize_t ret = 0;
2459 if (r->send_len) {
2460 ret = UDSTpSend(srv->tp, r->send_buf, r->send_len, NULL);
2461 }
2462
2463 // TODO test injection of transport errors:
2464 if (ret < 0) {
2465 UDSErr_t err = UDS_ERR_TPORT;
2466 EmitEvent(srv, UDS_EVT_Err, &err);
2467 UDS_LOGE(__FILE__, "UDSTpSend failed with %zd\n", ret);
2468 }
2469
2470 if (srv->RCRRP) {
2471 // ISO14229-2:2013 Table 4 footnote b
2472 // min time between consecutive 0x78 responses is 0.3 * p2*
2473 uint32_t wait_time = srv->p2_star_ms * 3 / 10;
2474 srv->p2_timer = UDSMillis() + wait_time;
2475 } else {
2476 srv->p2_timer = UDSMillis() + srv->p2_ms;
2477 srv->requestInProgress = false;
2478 }
2479 }
2480
2481 } else {
2482 if (srv->notReadyToReceive) {
2483 return; // cannot respond to request right now
2484 }
2485 ssize_t len = UDSTpRecv(srv->tp, r->recv_buf, sizeof(r->recv_buf), &r->info);
2486 if (len < 0) {
2487 UDS_LOGE(__FILE__, "UDSTpRecv failed with %zd\n", r->recv_len);
2488 return;
2489 }
2490
2491 r->recv_len = (size_t)len;
2492
2493 if (r->recv_len > 0) {
2494 UDSErr_t response = evaluateServiceResponse(srv, r);
2495 srv->requestInProgress = true;
2496 if (UDS_NRC_RequestCorrectlyReceived_ResponsePending == response) {
2497 srv->RCRRP = true;
2498 }
2499 }
2500 }
2501}
2502
2503
2504#ifdef UDS_LINES
2505#line 1 "src/tp.c"
2506#endif
2507
2508ssize_t UDSTpSend(struct UDSTp *hdl, const uint8_t *buf, ssize_t len, UDSSDU_t *info) {
2509 UDS_ASSERT(hdl);
2510 UDS_ASSERT(hdl->send);
2511 return hdl->send(hdl, (uint8_t *)buf, len, info);
2512}
2513
2514ssize_t UDSTpRecv(struct UDSTp *hdl, uint8_t *buf, size_t bufsize, UDSSDU_t *info) {
2515 UDS_ASSERT(hdl);
2516 UDS_ASSERT(hdl->recv);
2517 return hdl->recv(hdl, buf, bufsize, info);
2518}
2519
2520UDSTpStatus_t UDSTpPoll(struct UDSTp *hdl) {
2521 UDS_ASSERT(hdl);
2522 UDS_ASSERT(hdl->poll);
2523 return hdl->poll(hdl);
2524}
2525
2526#ifdef UDS_LINES
2527#line 1 "src/util.c"
2528#endif
2529
2530#if UDS_CUSTOM_MILLIS
2531#else
2532uint32_t UDSMillis(void) {
2533#if UDS_SYS == UDS_SYS_UNIX
2534 struct timeval te;
2535 gettimeofday(&te, NULL); // cppcheck-suppress misra-c2012-21.6
2536 long long milliseconds = (te.tv_sec * 1000LL) + (te.tv_usec / 1000);
2537 return (uint32_t)milliseconds;
2538#elif UDS_SYS == UDS_SYS_WINDOWS
2539 struct timespec ts;
2540 timespec_get(&ts, TIME_UTC);
2541 long long milliseconds = ts.tv_sec * 1000LL + ts.tv_nsec / 1000000;
2542 return (uint32_t)milliseconds;
2543#elif UDS_SYS == UDS_SYS_ARDUINO
2544 return millis();
2545#elif UDS_SYS == UDS_SYS_ESP32
2546 return esp_timer_get_time() / 1000;
2547#else
2548#error "UDSMillis() undefined!"
2549#endif
2550}
2551#endif
2552
2553/**
2554 * @brief Check if a security level is reserved per ISO14229-1:2020 Table 42
2555 *
2556 * @param securityLevel
2557 * @return true
2558 * @return false
2559 */
2560bool UDSSecurityAccessLevelIsReserved(uint8_t subFunction) {
2561 uint8_t securityLevel = subFunction & 0x3F;
2562 if (0u == securityLevel) {
2563 return true;
2564 }
2565 if ((securityLevel >= 0x43u) && (securityLevel <= 0x5Eu)) {
2566 return true;
2567 }
2568 if (securityLevel == 0x7Fu) {
2569 return true;
2570 }
2571 return false;
2572}
2573
2574const char *UDSErrToStr(UDSErr_t err) {
2575 switch (err) {
2576 case UDS_OK:
2577 return "UDS_OK";
2578 case UDS_FAIL:
2579 return "UDS_FAIL";
2580 case UDS_NRC_GeneralReject:
2581 return "UDS_NRC_GeneralReject";
2582 case UDS_NRC_ServiceNotSupported:
2583 return "UDS_NRC_ServiceNotSupported";
2584 case UDS_NRC_SubFunctionNotSupported:
2585 return "UDS_NRC_SubFunctionNotSupported";
2586 case UDS_NRC_IncorrectMessageLengthOrInvalidFormat:
2587 return "UDS_NRC_IncorrectMessageLengthOrInvalidFormat";
2588 case UDS_NRC_ResponseTooLong:
2589 return "UDS_NRC_ResponseTooLong";
2590 case UDS_NRC_BusyRepeatRequest:
2591 return "UDS_NRC_BusyRepeatRequest";
2592 case UDS_NRC_ConditionsNotCorrect:
2593 return "UDS_NRC_ConditionsNotCorrect";
2594 case UDS_NRC_RequestSequenceError:
2595 return "UDS_NRC_RequestSequenceError";
2596 case UDS_NRC_NoResponseFromSubnetComponent:
2597 return "UDS_NRC_NoResponseFromSubnetComponent";
2598 case UDS_NRC_FailurePreventsExecutionOfRequestedAction:
2599 return "UDS_NRC_FailurePreventsExecutionOfRequestedAction";
2600 case UDS_NRC_RequestOutOfRange:
2601 return "UDS_NRC_RequestOutOfRange";
2602 case UDS_NRC_SecurityAccessDenied:
2603 return "UDS_NRC_SecurityAccessDenied";
2604 case UDS_NRC_AuthenticationRequired:
2605 return "UDS_NRC_AuthenticationRequired";
2606 case UDS_NRC_InvalidKey:
2607 return "UDS_NRC_InvalidKey";
2608 case UDS_NRC_ExceedNumberOfAttempts:
2609 return "UDS_NRC_ExceedNumberOfAttempts";
2610 case UDS_NRC_RequiredTimeDelayNotExpired:
2611 return "UDS_NRC_RequiredTimeDelayNotExpired";
2612 case UDS_NRC_SecureDataTransmissionRequired:
2613 return "UDS_NRC_SecureDataTransmissionRequired";
2614 case UDS_NRC_SecureDataTransmissionNotAllowed:
2615 return "UDS_NRC_SecureDataTransmissionNotAllowed";
2616 case UDS_NRC_SecureDataVerificationFailed:
2617 return "UDS_NRC_SecureDataVerificationFailed";
2618 case UDS_NRC_CertficateVerificationFailedInvalidTimePeriod:
2619 return "UDS_NRC_CertficateVerificationFailedInvalidTimePeriod";
2620 case UDS_NRC_CertficateVerificationFailedInvalidSignature:
2621 return "UDS_NRC_CertficateVerificationFailedInvalidSignature";
2622 case UDS_NRC_CertficateVerificationFailedInvalidChainOfTrust:
2623 return "UDS_NRC_CertficateVerificationFailedInvalidChainOfTrust";
2624 case UDS_NRC_CertficateVerificationFailedInvalidType:
2625 return "UDS_NRC_CertficateVerificationFailedInvalidType";
2626 case UDS_NRC_CertficateVerificationFailedInvalidFormat:
2627 return "UDS_NRC_CertficateVerificationFailedInvalidFormat";
2628 case UDS_NRC_CertficateVerificationFailedInvalidContent:
2629 return "UDS_NRC_CertficateVerificationFailedInvalidContent";
2630 case UDS_NRC_CertficateVerificationFailedInvalidScope:
2631 return "UDS_NRC_CertficateVerificationFailedInvalidScope";
2632 case UDS_NRC_CertficateVerificationFailedInvalidCertificate:
2633 return "UDS_NRC_CertficateVerificationFailedInvalidCertificate";
2634 case UDS_NRC_OwnershipVerificationFailed:
2635 return "UDS_NRC_OwnershipVerificationFailed";
2636 case UDS_NRC_ChallengeCalculationFailed:
2637 return "UDS_NRC_ChallengeCalculationFailed";
2638 case UDS_NRC_SettingAccessRightsFailed:
2639 return "UDS_NRC_SettingAccessRightsFailed";
2640 case UDS_NRC_SessionKeyCreationOrDerivationFailed:
2641 return "UDS_NRC_SessionKeyCreationOrDerivationFailed";
2642 case UDS_NRC_ConfigurationDataUsageFailed:
2643 return "UDS_NRC_ConfigurationDataUsageFailed";
2644 case UDS_NRC_DeAuthenticationFailed:
2645 return "UDS_NRC_DeAuthenticationFailed";
2646 case UDS_NRC_UploadDownloadNotAccepted:
2647 return "UDS_NRC_UploadDownloadNotAccepted";
2648 case UDS_NRC_TransferDataSuspended:
2649 return "UDS_NRC_TransferDataSuspended";
2650 case UDS_NRC_GeneralProgrammingFailure:
2651 return "UDS_NRC_GeneralProgrammingFailure";
2652 case UDS_NRC_WrongBlockSequenceCounter:
2653 return "UDS_NRC_WrongBlockSequenceCounter";
2654 case UDS_NRC_RequestCorrectlyReceived_ResponsePending:
2655 return "UDS_NRC_RequestCorrectlyReceived_ResponsePending";
2656 case UDS_NRC_SubFunctionNotSupportedInActiveSession:
2657 return "UDS_NRC_SubFunctionNotSupportedInActiveSession";
2658 case UDS_NRC_ServiceNotSupportedInActiveSession:
2659 return "UDS_NRC_ServiceNotSupportedInActiveSession";
2660 case UDS_NRC_RpmTooHigh:
2661 return "UDS_NRC_RpmTooHigh";
2662 case UDS_NRC_RpmTooLow:
2663 return "UDS_NRC_RpmTooLow";
2664 case UDS_NRC_EngineIsRunning:
2665 return "UDS_NRC_EngineIsRunning";
2666 case UDS_NRC_EngineIsNotRunning:
2667 return "UDS_NRC_EngineIsNotRunning";
2668 case UDS_NRC_EngineRunTimeTooLow:
2669 return "UDS_NRC_EngineRunTimeTooLow";
2670 case UDS_NRC_TemperatureTooHigh:
2671 return "UDS_NRC_TemperatureTooHigh";
2672 case UDS_NRC_TemperatureTooLow:
2673 return "UDS_NRC_TemperatureTooLow";
2674 case UDS_NRC_VehicleSpeedTooHigh:
2675 return "UDS_NRC_VehicleSpeedTooHigh";
2676 case UDS_NRC_VehicleSpeedTooLow:
2677 return "UDS_NRC_VehicleSpeedTooLow";
2678 case UDS_NRC_ThrottlePedalTooHigh:
2679 return "UDS_NRC_ThrottlePedalTooHigh";
2680 case UDS_NRC_ThrottlePedalTooLow:
2681 return "UDS_NRC_ThrottlePedalTooLow";
2682 case UDS_NRC_TransmissionRangeNotInNeutral:
2683 return "UDS_NRC_TransmissionRangeNotInNeutral";
2684 case UDS_NRC_TransmissionRangeNotInGear:
2685 return "UDS_NRC_TransmissionRangeNotInGear";
2686 case UDS_NRC_BrakeSwitchNotClosed:
2687 return "UDS_NRC_BrakeSwitchNotClosed";
2688 case UDS_NRC_ShifterLeverNotInPark:
2689 return "UDS_NRC_ShifterLeverNotInPark";
2690 case UDS_NRC_TorqueConverterClutchLocked:
2691 return "UDS_NRC_TorqueConverterClutchLocked";
2692 case UDS_NRC_VoltageTooHigh:
2693 return "UDS_NRC_VoltageTooHigh";
2694 case UDS_NRC_VoltageTooLow:
2695 return "UDS_NRC_VoltageTooLow";
2696 case UDS_NRC_ResourceTemporarilyNotAvailable:
2697 return "UDS_NRC_ResourceTemporarilyNotAvailable";
2698 case UDS_ERR_TIMEOUT:
2699 return "UDS_ERR_TIMEOUT";
2700 case UDS_ERR_DID_MISMATCH:
2701 return "UDS_ERR_DID_MISMATCH";
2702 case UDS_ERR_SID_MISMATCH:
2703 return "UDS_ERR_SID_MISMATCH";
2704 case UDS_ERR_SUBFUNCTION_MISMATCH:
2705 return "UDS_ERR_SUBFUNCTION_MISMATCH";
2706 case UDS_ERR_TPORT:
2707 return "UDS_ERR_TPORT";
2708 case UDS_ERR_RESP_TOO_SHORT:
2709 return "UDS_ERR_RESP_TOO_SHORT";
2710 case UDS_ERR_BUFSIZ:
2711 return "UDS_ERR_BUFSIZ";
2712 case UDS_ERR_INVALID_ARG:
2713 return "UDS_ERR_INVALID_ARG";
2714 case UDS_ERR_BUSY:
2715 return "UDS_ERR_BUSY";
2716 case UDS_ERR_MISUSE:
2717 return "UDS_ERR_MISUSE";
2718 default:
2719 return "unknown";
2720 }
2721}
2722
2723const char *UDSEventToStr(UDSEvent_t evt) {
2724
2725 switch (evt) {
2726 case UDS_EVT_Custom:
2727 return "UDS_EVT_Custom";
2728 case UDS_EVT_Err:
2729 return "UDS_EVT_Err";
2731 return "UDS_EVT_DiagSessCtrl";
2732 case UDS_EVT_EcuReset:
2733 return "UDS_EVT_EcuReset";
2735 return "UDS_EVT_ReadDataByIdent";
2737 return "UDS_EVT_ReadMemByAddr";
2738 case UDS_EVT_CommCtrl:
2739 return "UDS_EVT_CommCtrl";
2741 return "UDS_EVT_SecAccessRequestSeed";
2743 return "UDS_EVT_SecAccessValidateKey";
2745 return "UDS_EVT_WriteDataByIdent";
2747 return "UDS_EVT_RoutineCtrl";
2749 return "UDS_EVT_RequestDownload";
2751 return "UDS_EVT_RequestUpload";
2753 return "UDS_EVT_TransferData";
2755 return "UDS_EVT_RequestTransferExit";
2757 return "UDS_EVT_SessionTimeout";
2759 return "UDS_EVT_DoScheduledReset";
2761 return "UDS_EVT_RequestFileTransfer";
2762 case UDS_EVT_Poll:
2763 return "UDS_EVT_Poll";
2765 return "UDS_EVT_SendComplete";
2767 return "UDS_EVT_ResponseReceived";
2768 case UDS_EVT_Idle:
2769 return "UDS_EVT_Idle";
2770 case UDS_EVT_MAX:
2771 return "UDS_EVT_MAX";
2772 default:
2773 return "unknown";
2774 }
2775}
2776
2777bool UDSErrIsNRC(UDSErr_t err) {
2778 switch (err) {
2779 case UDS_PositiveResponse:
2780 case UDS_NRC_GeneralReject:
2781 case UDS_NRC_ServiceNotSupported:
2782 case UDS_NRC_SubFunctionNotSupported:
2783 case UDS_NRC_IncorrectMessageLengthOrInvalidFormat:
2784 case UDS_NRC_ResponseTooLong:
2785 case UDS_NRC_BusyRepeatRequest:
2786 case UDS_NRC_ConditionsNotCorrect:
2787 case UDS_NRC_RequestSequenceError:
2788 case UDS_NRC_NoResponseFromSubnetComponent:
2789 case UDS_NRC_FailurePreventsExecutionOfRequestedAction:
2790 case UDS_NRC_RequestOutOfRange:
2791 case UDS_NRC_SecurityAccessDenied:
2792 case UDS_NRC_AuthenticationRequired:
2793 case UDS_NRC_InvalidKey:
2794 case UDS_NRC_ExceedNumberOfAttempts:
2795 case UDS_NRC_RequiredTimeDelayNotExpired:
2796 case UDS_NRC_SecureDataTransmissionRequired:
2797 case UDS_NRC_SecureDataTransmissionNotAllowed:
2798 case UDS_NRC_SecureDataVerificationFailed:
2799 case UDS_NRC_CertficateVerificationFailedInvalidTimePeriod:
2800 case UDS_NRC_CertficateVerificationFailedInvalidSignature:
2801 case UDS_NRC_CertficateVerificationFailedInvalidChainOfTrust:
2802 case UDS_NRC_CertficateVerificationFailedInvalidType:
2803 case UDS_NRC_CertficateVerificationFailedInvalidFormat:
2804 case UDS_NRC_CertficateVerificationFailedInvalidContent:
2805 case UDS_NRC_CertficateVerificationFailedInvalidScope:
2806 case UDS_NRC_CertficateVerificationFailedInvalidCertificate:
2807 case UDS_NRC_OwnershipVerificationFailed:
2808 case UDS_NRC_ChallengeCalculationFailed:
2809 case UDS_NRC_SettingAccessRightsFailed:
2810 case UDS_NRC_SessionKeyCreationOrDerivationFailed:
2811 case UDS_NRC_ConfigurationDataUsageFailed:
2812 case UDS_NRC_DeAuthenticationFailed:
2813 case UDS_NRC_UploadDownloadNotAccepted:
2814 case UDS_NRC_TransferDataSuspended:
2815 case UDS_NRC_GeneralProgrammingFailure:
2816 case UDS_NRC_WrongBlockSequenceCounter:
2817 case UDS_NRC_RequestCorrectlyReceived_ResponsePending:
2818 case UDS_NRC_SubFunctionNotSupportedInActiveSession:
2819 case UDS_NRC_ServiceNotSupportedInActiveSession:
2820 case UDS_NRC_RpmTooHigh:
2821 case UDS_NRC_RpmTooLow:
2822 case UDS_NRC_EngineIsRunning:
2823 case UDS_NRC_EngineIsNotRunning:
2824 case UDS_NRC_EngineRunTimeTooLow:
2825 case UDS_NRC_TemperatureTooHigh:
2826 case UDS_NRC_TemperatureTooLow:
2827 case UDS_NRC_VehicleSpeedTooHigh:
2828 case UDS_NRC_VehicleSpeedTooLow:
2829 case UDS_NRC_ThrottlePedalTooHigh:
2830 case UDS_NRC_ThrottlePedalTooLow:
2831 case UDS_NRC_TransmissionRangeNotInNeutral:
2832 case UDS_NRC_TransmissionRangeNotInGear:
2833 case UDS_NRC_BrakeSwitchNotClosed:
2834 case UDS_NRC_ShifterLeverNotInPark:
2835 case UDS_NRC_TorqueConverterClutchLocked:
2836 case UDS_NRC_VoltageTooHigh:
2837 case UDS_NRC_VoltageTooLow:
2838 case UDS_NRC_ResourceTemporarilyNotAvailable:
2839 return true;
2840 default:
2841 return false;
2842 }
2843}
2844
2845
2846#ifdef UDS_LINES
2847#line 1 "src/log.c"
2848#endif
2849#include <stdio.h>
2850#include <stdarg.h>
2851
2852#if UDS_LOG_LEVEL > UDS_LOG_NONE
2853void UDS_LogWrite(UDS_LogLevel_t level, const char *tag, const char *format, ...) {
2854 va_list list;
2855 (void)level;
2856 (void)tag;
2857 va_start(list, format);
2858 vprintf(format, list);
2859 va_end(list);
2860}
2861
2862void UDS_LogSDUInternal(UDS_LogLevel_t level, const char *tag, const uint8_t *buffer,
2863 size_t buff_len, UDSSDU_t *info) {
2864 (void)info;
2865 for (unsigned i = 0; i < buff_len; i++) {
2866 UDS_LogWrite(level, tag, "%02x ", buffer[i]);
2867 }
2868 UDS_LogWrite(level, tag, "\n");
2869}
2870#endif
2871
2872
2873#ifdef UDS_LINES
2874#line 1 "src/tp/isotp_c.c"
2875#endif
2876#if defined(UDS_TP_ISOTP_C)
2877
2878
2879static UDSTpStatus_t tp_poll(UDSTp_t *hdl) {
2880 UDS_ASSERT(hdl);
2881 UDSTpStatus_t status = 0;
2882 UDSISOTpC_t *impl = (UDSISOTpC_t *)hdl;
2883 isotp_poll(&impl->phys_link);
2884 if (impl->phys_link.send_status == ISOTP_SEND_STATUS_INPROGRESS) {
2885 status |= UDS_TP_SEND_IN_PROGRESS;
2886 }
2887 return status;
2888}
2889
2890static ssize_t tp_send(UDSTp_t *hdl, uint8_t *buf, size_t len, UDSSDU_t *info) {
2891 UDS_ASSERT(hdl);
2892 ssize_t ret = -1;
2893 UDSISOTpC_t *tp = (UDSISOTpC_t *)hdl;
2894 IsoTpLink *link = NULL;
2895 const UDSTpAddr_t ta_type = info ? info->A_TA_Type : UDS_A_TA_TYPE_PHYSICAL;
2896 switch (ta_type) {
2897 case UDS_A_TA_TYPE_PHYSICAL:
2898 link = &tp->phys_link;
2899 break;
2900 case UDS_A_TA_TYPE_FUNCTIONAL:
2901 link = &tp->func_link;
2902 if (len > 7) {
2903 UDS_LOGI(__FILE__, "Cannot send more than 7 bytes via functional addressing\n");
2904 ret = -3;
2905 goto done;
2906 }
2907 break;
2908 default:
2909 ret = -4;
2910 goto done;
2911 }
2912
2913 int send_status = isotp_send(link, buf, len);
2914 switch (send_status) {
2915 case ISOTP_RET_OK:
2916 ret = len;
2917 goto done;
2918 case ISOTP_RET_INPROGRESS:
2919 case ISOTP_RET_OVERFLOW:
2920 default:
2921 ret = send_status;
2922 goto done;
2923 }
2924done:
2925 return ret;
2926}
2927
2928static ssize_t tp_recv(UDSTp_t *hdl, uint8_t *buf, size_t bufsize, UDSSDU_t *info) {
2929 UDS_ASSERT(hdl);
2930 UDS_ASSERT(buf);
2931 uint16_t out_size = 0;
2932 UDSISOTpC_t *tp = (UDSISOTpC_t *)hdl;
2933
2934 int ret = isotp_receive(&tp->phys_link, buf, bufsize, &out_size);
2935 if (ret == ISOTP_RET_OK) {
2936 UDS_LOGI(__FILE__, "phys link received %d bytes", out_size);
2937 if (NULL != info) {
2938 info->A_TA = tp->phys_sa;
2939 info->A_SA = tp->phys_ta;
2940 info->A_TA_Type = UDS_A_TA_TYPE_PHYSICAL;
2941 }
2942 } else if (ret == ISOTP_RET_NO_DATA) {
2943 ret = isotp_receive(&tp->func_link, buf, bufsize, &out_size);
2944 if (ret == ISOTP_RET_OK) {
2945 UDS_LOGI(__FILE__, "func link received %d bytes", out_size);
2946 if (NULL != info) {
2947 info->A_TA = tp->func_sa;
2948 info->A_SA = tp->func_ta;
2949 info->A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL;
2950 }
2951 } else if (ret == ISOTP_RET_NO_DATA) {
2952 return 0;
2953 } else {
2954 UDS_LOGE(__FILE__, "unhandled return code from func link %d\n", ret);
2955 }
2956 } else {
2957 UDS_LOGE(__FILE__, "unhandled return code from phys link %d\n", ret);
2958 }
2959 return out_size;
2960}
2961
2962UDSErr_t UDSISOTpCInit(UDSISOTpC_t *tp, const UDSISOTpCConfig_t *cfg) {
2963 if (cfg == NULL || tp == NULL) {
2964 return UDS_ERR_INVALID_ARG;
2965 }
2966 tp->hdl.poll = tp_poll;
2967 tp->hdl.send = tp_send;
2968 tp->hdl.recv = tp_recv;
2969 tp->phys_sa = cfg->source_addr;
2970 tp->phys_ta = cfg->target_addr;
2971 tp->func_sa = cfg->source_addr_func;
2972 tp->func_ta = cfg->target_addr_func;
2973
2974 isotp_init_link(&tp->phys_link, tp->phys_ta, tp->send_buf, sizeof(tp->send_buf), tp->recv_buf,
2975 sizeof(tp->recv_buf));
2976 isotp_init_link(&tp->func_link, tp->func_ta, tp->recv_buf, sizeof(tp->send_buf), tp->recv_buf,
2977 sizeof(tp->recv_buf));
2978 return UDS_OK;
2979}
2980
2981#endif
2982
2983
2984#ifdef UDS_LINES
2985#line 1 "src/tp/isotp_c_socketcan.c"
2986#endif
2987#if defined(UDS_TP_ISOTP_C_SOCKETCAN)
2988
2989#include <linux/can.h>
2990#include <linux/can/raw.h>
2991#include <net/if.h>
2992#include <stdbool.h>
2993#include <stdint.h>
2994#include <stdlib.h>
2995#include <sys/ioctl.h>
2996#include <unistd.h>
2997#include <errno.h>
2998#include <stdarg.h>
2999
3000static int SetupSocketCAN(const char *ifname) {
3001 struct sockaddr_can addr = {0};
3002 struct ifreq ifr = {0};
3003 int sockfd = -1;
3004
3005 if ((sockfd = socket(PF_CAN, SOCK_RAW | SOCK_NONBLOCK, CAN_RAW)) < 0) {
3006 perror("socket");
3007 goto done;
3008 }
3009
3010 memset(&ifr, 0, sizeof(ifr));
3011 if (snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", ifname) >= (int)sizeof(ifr.ifr_name)) {
3012 UDS_LOGE(__FILE__, "Interface name too long");
3013 close(sockfd);
3014 sockfd = -1;
3015 goto done;
3016 }
3017 ioctl(sockfd, SIOCGIFINDEX, &ifr);
3018 memset(&addr, 0, sizeof(addr));
3019 addr.can_family = AF_CAN;
3020 addr.can_ifindex = ifr.ifr_ifindex;
3021 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
3022 perror("bind");
3023 }
3024
3025done:
3026 return sockfd;
3027}
3028
3029uint32_t isotp_user_get_us(void) { return UDSMillis() * 1000; }
3030
3031__attribute__((format(printf, 1, 2))) void isotp_user_debug(const char *message, ...) {
3032 va_list args;
3033 va_start(args, message);
3034 vprintf(message, args);
3035 va_end(args);
3036}
3037
3038#ifndef ISO_TP_USER_SEND_CAN_ARG
3039#error "ISO_TP_USER_SEND_CAN_ARG must be defined"
3040#endif
3041int isotp_user_send_can(const uint32_t arbitration_id, const uint8_t *data, const uint8_t size,
3042 void *user_data) {
3043 (void)fflush(stdout);
3044 UDS_ASSERT(user_data);
3045 int sockfd = *(int *)user_data;
3046 struct can_frame frame = {0};
3047 frame.can_id = arbitration_id;
3048 frame.can_dlc = size;
3049 memmove(frame.data, data, size);
3050 if (write(sockfd, &frame, sizeof(struct can_frame)) != sizeof(struct can_frame)) {
3051 perror("Write err");
3052 return ISOTP_RET_ERROR;
3053 }
3054 return ISOTP_RET_OK;
3055}
3056
3057static void SocketCANRecv(UDSTpISOTpC_t *tp) {
3058 UDS_ASSERT(tp);
3059 struct can_frame frame = {0};
3060 int nbytes = 0;
3061
3062 for (;;) {
3063 nbytes = read(tp->fd, &frame, sizeof(struct can_frame));
3064 if (nbytes < 0) {
3065 if (EAGAIN == errno || EWOULDBLOCK == errno) {
3066 break;
3067 } else {
3068 perror("read");
3069 }
3070 } else if (nbytes == 0) {
3071 break;
3072 } else {
3073 if (frame.can_id == tp->phys_sa) {
3074 isotp_on_can_message(&tp->phys_link, frame.data, frame.can_dlc);
3075 } else if (frame.can_id == tp->func_sa) {
3076 if (ISOTP_RECEIVE_STATUS_IDLE != tp->phys_link.receive_status) {
3077 UDS_LOGI(__FILE__,
3078 "func frame received but cannot process because link is not idle");
3079 return;
3080 }
3081 // TODO: reject if it's longer than a single frame
3082 isotp_on_can_message(&tp->func_link, frame.data, frame.can_dlc);
3083 }
3084 }
3085 }
3086}
3087
3088static UDSTpStatus_t isotp_c_socketcan_tp_poll(UDSTp_t *hdl) {
3089 UDS_ASSERT(hdl);
3090 UDSTpStatus_t status = 0;
3091 UDSTpISOTpC_t *impl = (UDSTpISOTpC_t *)hdl;
3092 SocketCANRecv(impl);
3093 isotp_poll(&impl->phys_link);
3094 if (impl->phys_link.send_status == ISOTP_SEND_STATUS_INPROGRESS) {
3095 status |= UDS_TP_SEND_IN_PROGRESS;
3096 }
3097 if (impl->phys_link.send_status == ISOTP_SEND_STATUS_ERROR) {
3098 status |= UDS_TP_ERR;
3099 }
3100 return status;
3101}
3102
3103static ssize_t isotp_c_socketcan_tp_send(UDSTp_t *hdl, uint8_t *buf, size_t len, UDSSDU_t *info) {
3104 UDS_ASSERT(hdl);
3105 ssize_t ret = -1;
3106 UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl;
3107 IsoTpLink *link = NULL;
3108 const UDSTpAddr_t ta_type = info ? info->A_TA_Type : UDS_A_TA_TYPE_PHYSICAL;
3109 const uint32_t ta = ta_type == UDS_A_TA_TYPE_PHYSICAL ? tp->phys_ta : tp->func_ta;
3110 switch (ta_type) {
3111 case UDS_A_TA_TYPE_PHYSICAL:
3112 link = &tp->phys_link;
3113 break;
3114 case UDS_A_TA_TYPE_FUNCTIONAL:
3115 link = &tp->func_link;
3116 if (len > 7) {
3117 UDS_LOGI(__FILE__, "Cannot send more than 7 bytes via functional addressing");
3118 ret = -3;
3119 goto done;
3120 }
3121 break;
3122 default:
3123 ret = -4;
3124 goto done;
3125 }
3126
3127 int send_status = isotp_send(link, buf, len);
3128 switch (send_status) {
3129 case ISOTP_RET_OK:
3130 ret = len;
3131 goto done;
3132 case ISOTP_RET_INPROGRESS:
3133 case ISOTP_RET_OVERFLOW:
3134 default:
3135 ret = send_status;
3136 goto done;
3137 }
3138done:
3139 UDS_LOGD(__FILE__, "'%s' sends %ld bytes to 0x%03x (%s)", tp->tag, len, ta,
3140 ta_type == UDS_A_TA_TYPE_PHYSICAL ? "phys" : "func");
3141 UDS_LOG_SDU(__FILE__, buf, len, info);
3142 return ret;
3143}
3144
3145static ssize_t isotp_c_socketcan_tp_recv(UDSTp_t *hdl, uint8_t *buf, size_t bufsize,
3146 UDSSDU_t *info) {
3147 UDS_ASSERT(hdl);
3148 UDS_ASSERT(buf);
3149 uint16_t out_size = 0;
3150 UDSTpISOTpC_t *tp = (UDSTpISOTpC_t *)hdl;
3151
3152 int ret = isotp_receive(&tp->phys_link, buf, bufsize, &out_size);
3153 if (ret == ISOTP_RET_OK) {
3154 UDS_LOGI(__FILE__, "phys link received %d bytes", out_size);
3155 if (NULL != info) {
3156 info->A_TA = tp->phys_sa;
3157 info->A_SA = tp->phys_ta;
3158 info->A_TA_Type = UDS_A_TA_TYPE_PHYSICAL;
3159 }
3160 } else if (ret == ISOTP_RET_NO_DATA) {
3161 ret = isotp_receive(&tp->func_link, buf, bufsize, &out_size);
3162 if (ret == ISOTP_RET_OK) {
3163 UDS_LOGI(__FILE__, "func link received %d bytes", out_size);
3164 if (NULL != info) {
3165 info->A_TA = tp->func_sa;
3166 info->A_SA = tp->func_ta;
3167 info->A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL;
3168 }
3169 } else if (ret == ISOTP_RET_NO_DATA) {
3170 return 0;
3171 } else {
3172 UDS_LOGE(__FILE__, "unhandled return code from func link %d\n", ret);
3173 }
3174 } else {
3175 UDS_LOGE(__FILE__, "unhandled return code from phys link %d\n", ret);
3176 }
3177 return out_size;
3178}
3179
3180UDSErr_t UDSTpISOTpCInit(UDSTpISOTpC_t *tp, const char *ifname, uint32_t source_addr,
3181 uint32_t target_addr, uint32_t source_addr_func,
3182 uint32_t target_addr_func) {
3183 UDS_ASSERT(tp);
3184 UDS_ASSERT(ifname);
3185 tp->hdl.poll = isotp_c_socketcan_tp_poll;
3186 tp->hdl.send = isotp_c_socketcan_tp_send;
3187 tp->hdl.recv = isotp_c_socketcan_tp_recv;
3188 tp->phys_sa = source_addr;
3189 tp->phys_ta = target_addr;
3190 tp->func_sa = source_addr_func;
3191 tp->func_ta = target_addr;
3192 tp->fd = SetupSocketCAN(ifname);
3193
3194 isotp_init_link(&tp->phys_link, target_addr, tp->send_buf, sizeof(tp->send_buf), tp->recv_buf,
3195 sizeof(tp->recv_buf));
3196 isotp_init_link(&tp->func_link, target_addr_func, tp->recv_buf, sizeof(tp->send_buf),
3197 tp->recv_buf, sizeof(tp->recv_buf));
3198
3199 tp->phys_link.user_send_can_arg = &(tp->fd);
3200 tp->func_link.user_send_can_arg = &(tp->fd);
3201
3202 return UDS_OK;
3203}
3204
3205void UDSTpISOTpCDeinit(UDSTpISOTpC_t *tp) {
3206 UDS_ASSERT(tp);
3207 close(tp->fd);
3208 tp->fd = -1;
3209}
3210
3211#endif
3212
3213
3214#ifdef UDS_LINES
3215#line 1 "src/tp/isotp_sock.c"
3216#endif
3217#if defined(UDS_TP_ISOTP_SOCK)
3218
3219#include <string.h>
3220#include <errno.h>
3221#include <linux/can.h>
3222#include <linux/can/isotp.h>
3223#include <net/if.h>
3224#include <poll.h>
3225#include <sys/ioctl.h>
3226#include <sys/socket.h>
3227#include <sys/socket.h>
3228#include <sys/types.h>
3229#include <unistd.h>
3230
3231static UDSTpStatus_t isotp_sock_tp_poll(UDSTp_t *hdl) {
3232 UDSTpIsoTpSock_t *impl = (UDSTpIsoTpSock_t *)hdl;
3233 UDSTpStatus_t status = 0;
3234 int ret = 0;
3235 int fds[2] = {impl->phys_fd, impl->func_fd};
3236 struct pollfd pfds[2] = {0};
3237 pfds[0].fd = impl->phys_fd;
3238 pfds[0].events = POLLERR | POLLOUT;
3239 pfds[0].revents = 0;
3240
3241 pfds[1].fd = impl->func_fd;
3242 pfds[1].events = POLLERR | POLLOUT;
3243 pfds[1].revents = 0;
3244
3245 ret = poll(pfds, 2, 1);
3246 if (ret < 0) {
3247 UDS_LOGE(__FILE__, "poll failed: %d", ret);
3248 status |= UDS_TP_ERR;
3249 } else if (ret == 0) {
3250 ; // timeout, no events
3251 } else {
3252 // poll() returned with events
3253 for (int i = 0; i < 2; i++) {
3254 struct pollfd pfd = pfds[i];
3255
3256 // Check for errors
3257 if (pfd.revents & POLLERR) {
3258 int pending_err = 0;
3259 socklen_t len = sizeof(pending_err);
3260 if (!getsockopt(fds[i], SOL_SOCKET, SO_ERROR, &pending_err, &len) && pending_err) {
3261 switch (pending_err) {
3262 case ECOMM:
3263 UDS_LOGE(__FILE__, "ECOMM: Communication error on send");
3264 status |= UDS_TP_ERR;
3265 break;
3266 default:
3267 UDS_LOGE(__FILE__, "Asynchronous socket error: %s (%d)",
3268 strerror(pending_err), pending_err);
3269 status |= UDS_TP_ERR;
3270 break;
3271 }
3272 } else {
3273 UDS_LOGE(__FILE__, "POLLERR was set, but no error returned via SO_ERROR?");
3274 }
3275 }
3276
3277 // Check if send is in progress on physical socket
3278 // Only check the physical socket (not functional) since that's what sends multi-frame
3279 if (fds[i] == impl->phys_fd && pfd.revents != 0) {
3280 // When POLLOUT is NOT set but other events are present, the socket cannot accept
3281 // writes because a multi-frame transmission is in progress.
3282 // See: https://lore.kernel.org/all/20230331125511.372783-1-michal.sojka@cvut.cz/
3283 // The kernel ISO-TP driver suppresses POLLOUT when tx.state != ISOTP_IDLE
3284 if (!(pfd.revents & POLLOUT)) {
3285 status |= UDS_TP_SEND_IN_PROGRESS;
3286 }
3287 }
3288 }
3289 }
3290 return status;
3291}
3292
3293static ssize_t tp_recv_once(int fd, uint8_t *buf, size_t size) {
3294 ssize_t ret = read(fd, buf, size);
3295 if (ret < 0) {
3296 if (EAGAIN == errno || EWOULDBLOCK == errno) {
3297 ret = 0;
3298 } else {
3299 UDS_LOGI(__FILE__, "read failed: %ld with errno: %d\n", ret, errno);
3300 if (EILSEQ == errno) {
3301 UDS_LOGI(__FILE__, "Perhaps I received multiple responses?");
3302 }
3303 }
3304 }
3305 return ret;
3306}
3307
3308static ssize_t isotp_sock_tp_recv(UDSTp_t *hdl, uint8_t *buf, size_t bufsize, UDSSDU_t *info) {
3309 UDS_ASSERT(hdl);
3310 UDS_ASSERT(buf);
3311 ssize_t ret = 0;
3312 UDSTpIsoTpSock_t *impl = (UDSTpIsoTpSock_t *)hdl;
3313 UDSSDU_t *msg = &impl->recv_info;
3314
3315 ret = tp_recv_once(impl->phys_fd, buf, bufsize);
3316 if (ret > 0) {
3317 msg->A_TA = impl->phys_sa;
3318 msg->A_SA = impl->phys_ta;
3319 msg->A_TA_Type = UDS_A_TA_TYPE_PHYSICAL;
3320 } else {
3321 ret = tp_recv_once(impl->func_fd, buf, bufsize);
3322 if (ret > 0) {
3323 msg->A_TA = impl->func_sa;
3324 msg->A_SA = impl->func_ta;
3325 msg->A_TA_Type = UDS_A_TA_TYPE_FUNCTIONAL;
3326 }
3327 }
3328
3329 if (ret > 0) {
3330 if (info) {
3331 *info = *msg;
3332 }
3333
3334 UDS_LOGD(__FILE__, "'%s' received %ld bytes from 0x%03x (%s), ", impl->tag, ret, msg->A_TA,
3335 msg->A_TA_Type == UDS_A_TA_TYPE_PHYSICAL ? "phys" : "func");
3336 UDS_LOG_SDU(__FILE__, impl->recv_buf, ret, msg);
3337 }
3338
3339 return ret;
3340}
3341
3342static ssize_t isotp_sock_tp_send(UDSTp_t *hdl, uint8_t *buf, size_t len, UDSSDU_t *info) {
3343 UDS_ASSERT(hdl);
3344 ssize_t ret = -1;
3345 UDSTpIsoTpSock_t *impl = (UDSTpIsoTpSock_t *)hdl;
3346 int fd;
3347 const UDSTpAddr_t ta_type = info ? info->A_TA_Type : UDS_A_TA_TYPE_PHYSICAL;
3348
3349 if (UDS_A_TA_TYPE_PHYSICAL == ta_type) {
3350 fd = impl->phys_fd;
3351 } else if (UDS_A_TA_TYPE_FUNCTIONAL == ta_type) {
3352 if (len > 7) {
3353 UDS_LOGI(__FILE__, "UDSTpIsoTpSock: functional request too large");
3354 return -1;
3355 }
3356 fd = impl->func_fd;
3357 } else {
3358 ret = -4;
3359 goto done;
3360 }
3361 ret = write(fd, buf, len);
3362 if (ret < 0) {
3363 perror("write");
3364 }
3365done:;
3366 int ta = ta_type == UDS_A_TA_TYPE_PHYSICAL ? impl->phys_ta : impl->func_ta;
3367 UDS_LOGD(__FILE__, "'%s' sends %ld bytes to 0x%03x (%s)", impl->tag, len, ta,
3368 ta_type == UDS_A_TA_TYPE_PHYSICAL ? "phys" : "func");
3369 UDS_LOG_SDU(__FILE__, buf, len, info);
3370
3371 return ret;
3372}
3373
3374static int LinuxSockBind(const char *if_name, uint32_t rxid, uint32_t txid, bool functional) {
3375 int fd = 0;
3376 if ((fd = socket(AF_CAN, SOCK_DGRAM | SOCK_NONBLOCK, CAN_ISOTP)) < 0) {
3377 perror("Socket");
3378 return -1;
3379 }
3380
3381 struct can_isotp_fc_options fcopts = {
3382 .bs = 0x10,
3383 .stmin = 3,
3384 .wftmax = 0,
3385 };
3386 if (setsockopt(fd, SOL_CAN_ISOTP, CAN_ISOTP_RECV_FC, &fcopts, sizeof(fcopts)) < 0) {
3387 perror("setsockopt");
3388 return -1;
3389 }
3390
3391 struct can_isotp_options opts;
3392 memset(&opts, 0, sizeof(opts));
3393
3394 if (functional) {
3395 UDS_LOGI(__FILE__, "configuring fd: %d as functional", fd);
3396 // configure the socket as listen-only to avoid sending FC frames
3397 opts.flags |= CAN_ISOTP_LISTEN_MODE;
3398 }
3399
3400 if (setsockopt(fd, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts)) < 0) {
3401 perror("setsockopt (isotp_options):");
3402 return -1;
3403 }
3404
3405 struct ifreq ifr;
3406 memset(&ifr, 0, sizeof(ifr));
3407 if (snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", if_name) >= (int)sizeof(ifr.ifr_name)) {
3408 UDS_LOGE(__FILE__, "Interface name too long");
3409 close(fd);
3410 return -1;
3411 }
3412 ioctl(fd, SIOCGIFINDEX, &ifr);
3413
3414 struct sockaddr_can addr;
3415 memset(&addr, 0, sizeof(addr));
3416 addr.can_family = AF_CAN;
3417 addr.can_addr.tp.rx_id = rxid;
3418 addr.can_addr.tp.tx_id = txid;
3419 addr.can_ifindex = ifr.ifr_ifindex;
3420
3421 if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
3422 UDS_LOGI(__FILE__, "Bind: %s %s\n", strerror(errno), if_name);
3423 return -1;
3424 }
3425 return fd;
3426}
3427
3428UDSErr_t UDSTpIsoTpSockInitServer(UDSTpIsoTpSock_t *tp, const char *ifname, uint32_t source_addr,
3429 uint32_t target_addr, uint32_t source_addr_func) {
3430 UDS_ASSERT(tp);
3431 memset(tp, 0, sizeof(*tp));
3432 tp->hdl.send = isotp_sock_tp_send;
3433 tp->hdl.recv = isotp_sock_tp_recv;
3434 tp->hdl.poll = isotp_sock_tp_poll;
3435 tp->phys_sa = source_addr;
3436 tp->phys_ta = target_addr;
3437 tp->func_sa = source_addr_func;
3438
3439 tp->phys_fd = LinuxSockBind(ifname, source_addr, target_addr, false);
3440 tp->func_fd = LinuxSockBind(ifname, source_addr_func, 0, true);
3441 if (tp->phys_fd < 0 || tp->func_fd < 0) {
3442 UDS_LOGI(__FILE__, "foo\n");
3443 (void)fflush(stdout);
3444 return UDS_FAIL;
3445 }
3446 const char *tag = "server";
3447 memmove(tp->tag, tag, strlen(tag));
3448 UDS_LOGI(__FILE__, "%s initialized phys link rx 0x%03x tx 0x%03x func link rx 0x%03x tx 0x%03x",
3449 strlen(tp->tag) ? tp->tag : "server", source_addr, target_addr, source_addr_func,
3450 target_addr);
3451 return UDS_OK;
3452}
3453
3454UDSErr_t UDSTpIsoTpSockInitClient(UDSTpIsoTpSock_t *tp, const char *ifname, uint32_t source_addr,
3455 uint32_t target_addr, uint32_t target_addr_func) {
3456 UDS_ASSERT(tp);
3457 memset(tp, 0, sizeof(*tp));
3458 tp->hdl.send = isotp_sock_tp_send;
3459 tp->hdl.recv = isotp_sock_tp_recv;
3460 tp->hdl.poll = isotp_sock_tp_poll;
3461 tp->func_ta = target_addr_func;
3462 tp->phys_ta = target_addr;
3463 tp->phys_sa = source_addr;
3464
3465 tp->phys_fd = LinuxSockBind(ifname, source_addr, target_addr, false);
3466 tp->func_fd = LinuxSockBind(ifname, 0, target_addr_func, true);
3467 if (tp->phys_fd < 0 || tp->func_fd < 0) {
3468 return UDS_FAIL;
3469 }
3470 const char *tag = "client";
3471 memmove(tp->tag, tag, strlen(tag));
3472 UDS_LOGI(__FILE__,
3473 "%s initialized phys link (fd %d) rx 0x%03x tx 0x%03x func link (fd %d) rx 0x%03x tx "
3474 "0x%03x",
3475 strlen(tp->tag) ? tp->tag : "client", tp->phys_fd, source_addr, target_addr,
3476 tp->func_fd, source_addr, target_addr_func);
3477 return UDS_OK;
3478}
3479
3480void UDSTpIsoTpSockDeinit(UDSTpIsoTpSock_t *tp) {
3481 if (tp) {
3482 if (close(tp->phys_fd) < 0) {
3483 perror("failed to close socket");
3484 }
3485 if (close(tp->func_fd) < 0) {
3486 perror("failed to close socket");
3487 }
3488 }
3489}
3490
3491#endif
3492
3493
3494#ifdef UDS_LINES
3495#line 1 "src/tp/isotp_mock.c"
3496#endif
3497#if defined(UDS_TP_ISOTP_MOCK)
3498
3499#include <assert.h>
3500#include <stddef.h>
3501#include <stdio.h>
3502#include <string.h>
3503#include <stdlib.h>
3504
3505#define MAX_NUM_TP 16
3506#define NUM_MSGS 8
3507static ISOTPMock_t *TPs[MAX_NUM_TP];
3508static unsigned TPCount = 0;
3509static FILE *LogFile = NULL;
3510static struct Msg {
3511 uint8_t buf[UDS_ISOTP_MTU];
3512 size_t len;
3513 UDSSDU_t info;
3514 uint32_t scheduled_tx_time;
3515 ISOTPMock_t *sender;
3516} msgs[NUM_MSGS];
3517static unsigned MsgCount = 0;
3518
3519static void NetworkPoll(void) {
3520 for (unsigned i = 0; i < MsgCount; i++) {
3521 if (UDSTimeAfter(UDSMillis(), msgs[i].scheduled_tx_time)) {
3522 bool found = false;
3523 for (unsigned j = 0; j < TPCount; j++) {
3524 ISOTPMock_t *tp = TPs[j];
3525 if (tp->sa_phys == msgs[i].info.A_TA || tp->sa_func == msgs[i].info.A_TA) {
3526 found = true;
3527 if (tp->recv_len > 0) {
3528 UDS_LOGW(__FILE__,
3529 "TPMock: %s recv buffer is already full. Message dropped",
3530 tp->name);
3531 continue;
3532 }
3533
3534 UDS_LOGD(__FILE__,
3535 "%s receives %ld bytes from TA=0x%03X (A_TA_Type=%s):", tp->name,
3536 msgs[i].len, msgs[i].info.A_TA,
3537 msgs[i].info.A_TA_Type == UDS_A_TA_TYPE_PHYSICAL ? "PHYSICAL"
3538 : "FUNCTIONAL");
3539 UDS_LOG_SDU(__FILE__, msgs[i].buf, msgs[i].len, &(msgs[i].info));
3540
3541 memmove(tp->recv_buf, msgs[i].buf, msgs[i].len);
3542 tp->recv_len = msgs[i].len;
3543 tp->recv_info = msgs[i].info;
3544 }
3545 }
3546
3547 if (!found) {
3548 UDS_LOGW(__FILE__, "TPMock: no matching receiver for message");
3549 }
3550
3551 for (unsigned j = i + 1; j < MsgCount; j++) {
3552 msgs[j - 1] = msgs[j];
3553 }
3554 MsgCount--;
3555 i--;
3556 }
3557 }
3558}
3559
3560static ssize_t mock_tp_send(struct UDSTp *hdl, uint8_t *buf, size_t len, UDSSDU_t *info) {
3561 UDS_ASSERT(hdl);
3562 ISOTPMock_t *tp = (ISOTPMock_t *)hdl;
3563 if (MsgCount >= NUM_MSGS) {
3564 UDS_LOGW(__FILE__, "mock_tp_send: too many messages in the queue");
3565 return -1;
3566 }
3567 struct Msg *m = &msgs[MsgCount++];
3568 UDSTpAddr_t ta_type =
3569 info == NULL ? (UDSTpAddr_t)UDS_A_TA_TYPE_PHYSICAL : (UDSTpAddr_t)info->A_TA_Type;
3570 m->len = len;
3571 m->info.A_AE = info == NULL ? 0 : info->A_AE;
3572 if (UDS_A_TA_TYPE_PHYSICAL == ta_type) {
3573 m->info.A_TA = tp->ta_phys;
3574 m->info.A_SA = tp->sa_phys;
3575 } else if (UDS_A_TA_TYPE_FUNCTIONAL == ta_type) {
3576
3577 // This condition is only true for standard CAN.
3578 // Technically CAN-FD may also be used in ISO-TP.
3579 // TODO: add profiles to isotp_mock
3580 if (len > 7) {
3581 UDS_LOGW(__FILE__, "mock_tp_send: functional message too long: %ld", len);
3582 return -1;
3583 }
3584 m->info.A_TA = tp->ta_func;
3585 m->info.A_SA = tp->sa_func;
3586 } else {
3587 UDS_LOGW(__FILE__, "mock_tp_send: unknown TA type: %d", ta_type);
3588 return -1;
3589 }
3590 m->info.A_TA_Type = ta_type;
3591 m->scheduled_tx_time = UDSMillis() + tp->send_tx_delay_ms;
3592 memmove(m->buf, buf, len);
3593
3594 UDS_LOGD(__FILE__, "%s sends %ld bytes to TA=0x%03X (A_TA_Type=%s):", tp->name, len,
3595 m->info.A_TA, m->info.A_TA_Type == UDS_A_TA_TYPE_PHYSICAL ? "PHYSICAL" : "FUNCTIONAL");
3596 UDS_LOG_SDU(__FILE__, buf, len, &m->info);
3597
3598 return len;
3599}
3600
3601static ssize_t mock_tp_recv(struct UDSTp *hdl, uint8_t *buf, size_t bufsize, UDSSDU_t *info) {
3602 UDS_ASSERT(hdl);
3603 ISOTPMock_t *tp = (ISOTPMock_t *)hdl;
3604 if (tp->recv_len == 0) {
3605 return 0;
3606 }
3607 if (bufsize < tp->recv_len) {
3608 UDS_LOGW(__FILE__, "mock_tp_recv: buffer too small: %ld < %ld", bufsize, tp->recv_len);
3609 return -1;
3610 }
3611 ssize_t len = (ssize_t)tp->recv_len;
3612 memmove(buf, tp->recv_buf, tp->recv_len);
3613 if (info) {
3614 *info = tp->recv_info;
3615 }
3616 tp->recv_len = 0;
3617 return len;
3618}
3619
3620static UDSTpStatus_t mock_tp_poll(struct UDSTp *hdl) {
3621 (void)hdl; // unused parameter
3622 NetworkPoll();
3623 // todo: make this status reflect TX time
3624 return UDS_TP_IDLE;
3625}
3626
3627static_assert(offsetof(ISOTPMock_t, hdl) == 0, "ISOTPMock_t must not have any members before hdl");
3628
3629static void ISOTPMockAttach(ISOTPMock_t *tp, ISOTPMockArgs_t *args) {
3630 UDS_ASSERT(tp);
3631 UDS_ASSERT(args);
3632 UDS_ASSERT(TPCount < MAX_NUM_TP);
3633 TPs[TPCount++] = tp;
3634 tp->hdl.send = mock_tp_send;
3635 tp->hdl.recv = mock_tp_recv;
3636 tp->hdl.poll = mock_tp_poll;
3637 tp->sa_func = args->sa_func;
3638 tp->sa_phys = args->sa_phys;
3639 tp->ta_func = args->ta_func;
3640 tp->ta_phys = args->ta_phys;
3641 tp->recv_len = 0;
3642 UDS_LOGV(__FILE__, "attached %s. TPCount: %d", tp->name, TPCount);
3643}
3644
3645static void ISOTPMockDetach(ISOTPMock_t *tp) {
3646 UDS_ASSERT(tp);
3647 for (unsigned i = 0; i < TPCount; i++) {
3648 if (TPs[i] == tp) {
3649 for (unsigned j = i + 1; j < TPCount; j++) {
3650 TPs[j - 1] = TPs[j];
3651 }
3652 TPCount--;
3653 UDS_LOGV(__FILE__, "TPMock: detached %s. TPCount: %d", tp->name, TPCount);
3654 return;
3655 }
3656 }
3657 UDS_ASSERT(false);
3658}
3659
3660UDSTp_t *ISOTPMockNew(const char *name, ISOTPMockArgs_t *args) {
3661 if (TPCount >= MAX_NUM_TP) {
3662 UDS_LOGI(__FILE__, "TPCount: %d, too many TPs\n", TPCount);
3663 return NULL;
3664 }
3665 ISOTPMock_t *tp = malloc(sizeof(ISOTPMock_t));
3666 memset(tp, 0, sizeof(ISOTPMock_t));
3667 if (name) {
3668 if (snprintf(tp->name, sizeof(tp->name), "%s", name) >= (int)sizeof(tp->name)) {
3669 UDS_LOGE(__FILE__, "Transport name too long, truncated");
3670 }
3671 } else {
3672 (void)snprintf(tp->name, sizeof(tp->name), "TPMock%u", TPCount);
3673 }
3674 ISOTPMockAttach(tp, args);
3675 return &tp->hdl;
3676}
3677
3678void ISOTPMockConnect(UDSTp_t *tp1, UDSTp_t *tp2);
3679
3680void ISOTPMockLogToFile(const char *filename) {
3681 if (LogFile) {
3682 (void)fprintf(stderr, "Log file is already open\n");
3683 return;
3684 }
3685 if (!filename) {
3686 (void)fprintf(stderr, "Filename is NULL\n");
3687 return;
3688 }
3689 // create file
3690 LogFile = fopen(filename, "w");
3691 if (!LogFile) {
3692 (void)fprintf(stderr, "Failed to open log file %s\n", filename);
3693 return;
3694 }
3695}
3696
3697void ISOTPMockLogToStdout(void) {
3698 if (LogFile) {
3699 return;
3700 }
3701 LogFile = stdout;
3702}
3703
3704void ISOTPMockReset(void) {
3705 memset(TPs, 0, sizeof(TPs));
3706 TPCount = 0;
3707 memset(msgs, 0, sizeof(msgs));
3708 MsgCount = 0;
3709}
3710
3711void ISOTPMockFree(UDSTp_t *tp) {
3712 ISOTPMock_t *tpm = (ISOTPMock_t *)tp;
3713 ISOTPMockDetach(tpm);
3714 free(tp);
3715}
3716
3717#endif
3718
3719#if defined(UDS_TP_ISOTP_C)
3720#ifndef ISO_TP_USER_SEND_CAN_ARG
3721#error
3722#endif
3723#include <stdint.h>
3724
3725///////////////////////////////////////////////////////
3726/// STATIC FUNCTIONS ///
3727///////////////////////////////////////////////////////
3728
3729/* st_min to microsecond */
3730static uint8_t isotp_us_to_st_min(uint32_t us) {
3731 if (us <= 127000) {
3732 if (us >= 100 && us <= 900) {
3733 return (uint8_t)(0xF0 + (us / 100));
3734 } else {
3735 return (uint8_t)(us / 1000u);
3736 }
3737 }
3738
3739 return 0;
3740}
3741
3742/* st_min to usec */
3743static uint32_t isotp_st_min_to_us(uint8_t st_min) {
3744 if (st_min <= 0x7F) {
3745 return st_min * 1000;
3746 } else if (st_min >= 0xF1 && st_min <= 0xF9) {
3747 return (st_min - 0xF0) * 100;
3748 }
3749 return 0;
3750}
3751
3752static int isotp_send_flow_control(const IsoTpLink* link, uint8_t flow_status, uint8_t block_size, uint32_t st_min_us) {
3753
3754 IsoTpCanMessage message;
3755 int ret;
3756 uint8_t size = 0;
3757
3758 /* setup message */
3759 message.as.flow_control.type = ISOTP_PCI_TYPE_FLOW_CONTROL_FRAME;
3760 message.as.flow_control.FS = flow_status;
3761 message.as.flow_control.BS = block_size;
3762 message.as.flow_control.STmin = isotp_us_to_st_min(st_min_us);
3763
3764 /* send message */
3765#ifdef ISO_TP_FRAME_PADDING
3766 (void) memset(message.as.flow_control.reserve, ISO_TP_FRAME_PADDING_VALUE, sizeof(message.as.flow_control.reserve));
3767 size = sizeof(message);
3768#else
3769 size = 3;
3770#endif
3771
3772 ret = isotp_user_send_can(link->send_arbitration_id, message.as.data_array.ptr, size
3773 #if defined (ISO_TP_USER_SEND_CAN_ARG)
3774 ,link->user_send_can_arg
3775 #endif
3776 );
3777
3778 return ret;
3779}
3780
3781static int isotp_send_single_frame(const IsoTpLink* link, uint32_t id) {
3782
3783 IsoTpCanMessage message;
3784 int ret;
3785 uint8_t size = 0;
3786 (void)id;
3787
3788 /* multi frame message length must greater than 7 */
3789 assert(link->send_size <= 7);
3790
3791 /* setup message */
3792 message.as.single_frame.type = ISOTP_PCI_TYPE_SINGLE;
3793 message.as.single_frame.SF_DL = (uint8_t) link->send_size;
3794 (void) memcpy(message.as.single_frame.data, link->send_buffer, link->send_size);
3795
3796 /* send message */
3797#ifdef ISO_TP_FRAME_PADDING
3798 (void) memset(message.as.single_frame.data + link->send_size, ISO_TP_FRAME_PADDING_VALUE, sizeof(message.as.single_frame.data) - link->send_size);
3799 size = sizeof(message);
3800#else
3801 size = link->send_size + 1;
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_first_frame(IsoTpLink* link, uint32_t id) {
3814
3815 IsoTpCanMessage message;
3816 int ret;
3817
3818 /* multi frame message length must greater than 7 */
3819 assert(link->send_size > 7);
3820
3821 /* setup message */
3822 message.as.first_frame.type = ISOTP_PCI_TYPE_FIRST_FRAME;
3823 message.as.first_frame.FF_DL_low = (uint8_t) link->send_size;
3824 message.as.first_frame.FF_DL_high = (uint8_t) (0x0F & (link->send_size >> 8));
3825 (void) memcpy(message.as.first_frame.data, link->send_buffer, sizeof(message.as.first_frame.data));
3826
3827 /* send message */
3828 ret = isotp_user_send_can(id, message.as.data_array.ptr, sizeof(message)
3829 #if defined (ISO_TP_USER_SEND_CAN_ARG)
3830 ,link->user_send_can_arg
3831 #endif
3832
3833 );
3834 if (ISOTP_RET_OK == ret) {
3835 link->send_offset += sizeof(message.as.first_frame.data);
3836 link->send_sn = 1;
3837 }
3838
3839 return ret;
3840}
3841
3842static int isotp_send_consecutive_frame(IsoTpLink* link) {
3843
3844 IsoTpCanMessage message;
3845 uint16_t data_length;
3846 int ret;
3847 uint8_t size = 0;
3848
3849 /* multi frame message length must greater than 7 */
3850 assert(link->send_size > 7);
3851
3852 /* setup message */
3853 message.as.consecutive_frame.type = TSOTP_PCI_TYPE_CONSECUTIVE_FRAME;
3854 message.as.consecutive_frame.SN = link->send_sn;
3855 data_length = link->send_size - link->send_offset;
3856 if (data_length > sizeof(message.as.consecutive_frame.data)) {
3857 data_length = sizeof(message.as.consecutive_frame.data);
3858 }
3859 (void) memcpy(message.as.consecutive_frame.data, link->send_buffer + link->send_offset, data_length);
3860
3861 /* send message */
3862#ifdef ISO_TP_FRAME_PADDING
3863 (void) memset(message.as.consecutive_frame.data + data_length, ISO_TP_FRAME_PADDING_VALUE, sizeof(message.as.consecutive_frame.data) - data_length);
3864 size = sizeof(message);
3865#else
3866 size = data_length + 1;
3867#endif
3868
3869 ret = isotp_user_send_can(link->send_arbitration_id,
3870 message.as.data_array.ptr, size
3871#if defined (ISO_TP_USER_SEND_CAN_ARG)
3872 ,link->user_send_can_arg
3873#endif
3874 );
3875
3876 if (ISOTP_RET_OK == ret) {
3877 link->send_offset += data_length;
3878 if (++(link->send_sn) > 0x0F) {
3879 link->send_sn = 0;
3880 }
3881 }
3882
3883 return ret;
3884}
3885
3886static int isotp_receive_single_frame(IsoTpLink* link, const IsoTpCanMessage* message, uint8_t len) {
3887 /* check data length */
3888 if ((0 == message->as.single_frame.SF_DL) || (message->as.single_frame.SF_DL > (len - 1))) {
3889 isotp_user_debug("Single-frame length too small.");
3890 return ISOTP_RET_LENGTH;
3891 }
3892
3893 /* copying data */
3894 (void) memcpy(link->receive_buffer, message->as.single_frame.data, message->as.single_frame.SF_DL);
3895 link->receive_size = message->as.single_frame.SF_DL;
3896
3897 return ISOTP_RET_OK;
3898}
3899
3900static int isotp_receive_first_frame(IsoTpLink *link, IsoTpCanMessage *message, uint8_t len) {
3901 uint16_t payload_length;
3902
3903 if (8 != len) {
3904 isotp_user_debug("First frame should be 8 bytes in length.");
3905 return ISOTP_RET_LENGTH;
3906 }
3907
3908 /* check data length */
3909 payload_length = message->as.first_frame.FF_DL_high;
3910 payload_length = (uint16_t)(payload_length << 8) + message->as.first_frame.FF_DL_low;
3911
3912 /* should not use multiple frame transmition */
3913 if (payload_length <= 7) {
3914 isotp_user_debug("Should not use multiple frame transmission.");
3915 return ISOTP_RET_LENGTH;
3916 }
3917
3918 if (payload_length > link->receive_buf_size) {
3919 isotp_user_debug("Multi-frame response too large for receiving buffer.");
3920 return ISOTP_RET_OVERFLOW;
3921 }
3922
3923 /* copying data */
3924 (void) memcpy(link->receive_buffer, message->as.first_frame.data, sizeof(message->as.first_frame.data));
3925 link->receive_size = payload_length;
3926 link->receive_offset = sizeof(message->as.first_frame.data);
3927 link->receive_sn = 1;
3928
3929 return ISOTP_RET_OK;
3930}
3931
3932static int isotp_receive_consecutive_frame(IsoTpLink *link, IsoTpCanMessage *message, uint8_t len) {
3933 uint16_t remaining_bytes;
3934
3935 /* check sn */
3936 if (link->receive_sn != message->as.consecutive_frame.SN) {
3937 return ISOTP_RET_WRONG_SN;
3938 }
3939
3940 /* check data length */
3941 remaining_bytes = link->receive_size - link->receive_offset;
3942 if (remaining_bytes > sizeof(message->as.consecutive_frame.data)) {
3943 remaining_bytes = sizeof(message->as.consecutive_frame.data);
3944 }
3945 if (remaining_bytes > len - 1) {
3946 isotp_user_debug("Consecutive frame too short.");
3947 return ISOTP_RET_LENGTH;
3948 }
3949
3950 /* copying data */
3951 (void) memcpy(link->receive_buffer + link->receive_offset, message->as.consecutive_frame.data, remaining_bytes);
3952
3953 link->receive_offset += remaining_bytes;
3954 if (++(link->receive_sn) > 0x0F) {
3955 link->receive_sn = 0;
3956 }
3957
3958 return ISOTP_RET_OK;
3959}
3960
3961static int isotp_receive_flow_control_frame(IsoTpLink *link, IsoTpCanMessage *message, uint8_t len) {
3962 /* unused args */
3963 (void) link;
3964 (void) message;
3965
3966 /* check message length */
3967 if (len < 3) {
3968 isotp_user_debug("Flow control frame too short.");
3969 return ISOTP_RET_LENGTH;
3970 }
3971
3972 return ISOTP_RET_OK;
3973}
3974
3975///////////////////////////////////////////////////////
3976/// PUBLIC FUNCTIONS ///
3977///////////////////////////////////////////////////////
3978
3979int isotp_send(IsoTpLink *link, const uint8_t payload[], uint16_t size) {
3980 return isotp_send_with_id(link, link->send_arbitration_id, payload, size);
3981}
3982
3983int isotp_send_with_id(IsoTpLink *link, uint32_t id, const uint8_t payload[], uint16_t size) {
3984 int ret;
3985
3986 if (link == 0x0) {
3987 isotp_user_debug("Link is null!");
3988 return ISOTP_RET_ERROR;
3989 }
3990
3991 if (size > link->send_buf_size) {
3992 isotp_user_debug("Message size too large. Increase ISO_TP_MAX_MESSAGE_SIZE to set a larger buffer\n");
3993 const int32_t messageSize = 128;
3994 char message[messageSize];
3995 int32_t writtenChars = sprintf(&message[0], "Attempted to send %d bytes; max size is %d!\n", size, link->send_buf_size);
3996
3997 assert(writtenChars <= messageSize);
3998 (void) writtenChars;
3999
4000 isotp_user_debug("%s", message);
4001 return ISOTP_RET_OVERFLOW;
4002 }
4003
4004 if (ISOTP_SEND_STATUS_INPROGRESS == link->send_status) {
4005 isotp_user_debug("Abort previous message, transmission in progress.\n");
4006 return ISOTP_RET_INPROGRESS;
4007 }
4008
4009 /* copy into local buffer */
4010 link->send_size = size;
4011 link->send_offset = 0;
4012 (void) memcpy(link->send_buffer, payload, size);
4013
4014 if (link->send_size < 8) {
4015 /* send single frame */
4016 ret = isotp_send_single_frame(link, id);
4017 } else {
4018 /* send multi-frame */
4019 ret = isotp_send_first_frame(link, id);
4020
4021 /* init multi-frame control flags */
4022 if (ISOTP_RET_OK == ret) {
4023 link->send_bs_remain = 0;
4024 link->send_st_min_us = 0;
4025 link->send_wtf_count = 0;
4026 link->send_timer_st = isotp_user_get_us();
4027 link->send_timer_bs = isotp_user_get_us() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT_US;
4028 link->send_protocol_result = ISOTP_PROTOCOL_RESULT_OK;
4029 link->send_status = ISOTP_SEND_STATUS_INPROGRESS;
4030 }
4031 }
4032
4033 return ret;
4034}
4035
4036void isotp_on_can_message(IsoTpLink* link, const uint8_t* data, uint8_t len) {
4037 IsoTpCanMessage message;
4038 int ret;
4039
4040 if (len < 2 || len > 8) {
4041 return;
4042 }
4043
4044 memcpy(message.as.data_array.ptr, data, len);
4045 memset(message.as.data_array.ptr + len, 0, sizeof(message.as.data_array.ptr) - len);
4046
4047 switch (message.as.common.type) {
4048 case ISOTP_PCI_TYPE_SINGLE: {
4049 /* update protocol result */
4050 if (ISOTP_RECEIVE_STATUS_INPROGRESS == link->receive_status) {
4051 link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_UNEXP_PDU;
4052 } else {
4053 link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_OK;
4054 }
4055
4056 /* handle message */
4057 ret = isotp_receive_single_frame(link, &message, len);
4058
4059 if (ISOTP_RET_OK == ret) {
4060 /* change status */
4061 link->receive_status = ISOTP_RECEIVE_STATUS_FULL;
4062 }
4063 break;
4064 }
4065 case ISOTP_PCI_TYPE_FIRST_FRAME: {
4066 /* update protocol result */
4067 if (ISOTP_RECEIVE_STATUS_INPROGRESS == link->receive_status) {
4068 link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_UNEXP_PDU;
4069 } else {
4070 link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_OK;
4071 }
4072
4073 /* handle message */
4074 ret = isotp_receive_first_frame(link, &message, len);
4075
4076 /* if overflow happened */
4077 if (ISOTP_RET_OVERFLOW == ret) {
4078 /* update protocol result */
4079 link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_BUFFER_OVFLW;
4080 /* change status */
4081 link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
4082 /* send error message */
4083 isotp_send_flow_control(link, PCI_FLOW_STATUS_OVERFLOW, 0, 0);
4084 break;
4085 }
4086
4087 /* if receive successful */
4088 if (ISOTP_RET_OK == ret) {
4089 /* change status */
4090 link->receive_status = ISOTP_RECEIVE_STATUS_INPROGRESS;
4091 /* send fc frame */
4092 link->receive_bs_count = ISO_TP_DEFAULT_BLOCK_SIZE;
4093 isotp_send_flow_control(link, PCI_FLOW_STATUS_CONTINUE, link->receive_bs_count, ISO_TP_DEFAULT_ST_MIN_US);
4094 /* refresh timer cs */
4095 link->receive_timer_cr = isotp_user_get_us() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT_US;
4096 }
4097
4098 break;
4099 }
4100 case TSOTP_PCI_TYPE_CONSECUTIVE_FRAME: {
4101 /* check if in receiving status */
4102 if (ISOTP_RECEIVE_STATUS_INPROGRESS != link->receive_status) {
4103 link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_UNEXP_PDU;
4104 break;
4105 }
4106
4107 /* handle message */
4108 ret = isotp_receive_consecutive_frame(link, &message, len);
4109
4110 /* if wrong sn */
4111 if (ISOTP_RET_WRONG_SN == ret) {
4112 link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_WRONG_SN;
4113 link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
4114 break;
4115 }
4116
4117 /* if success */
4118 if (ISOTP_RET_OK == ret) {
4119 /* refresh timer cs */
4120 link->receive_timer_cr = isotp_user_get_us() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT_US;
4121
4122 /* receive finished */
4123 if (link->receive_offset >= link->receive_size) {
4124 link->receive_status = ISOTP_RECEIVE_STATUS_FULL;
4125 } else {
4126 /* send fc when bs reaches limit */
4127 if (0 == --link->receive_bs_count) {
4128 link->receive_bs_count = ISO_TP_DEFAULT_BLOCK_SIZE;
4129 isotp_send_flow_control(link, PCI_FLOW_STATUS_CONTINUE, link->receive_bs_count, ISO_TP_DEFAULT_ST_MIN_US);
4130 }
4131 }
4132 }
4133
4134 break;
4135 }
4136 case ISOTP_PCI_TYPE_FLOW_CONTROL_FRAME:
4137 /* handle fc frame only when sending in progress */
4138 if (ISOTP_SEND_STATUS_INPROGRESS != link->send_status) {
4139 break;
4140 }
4141
4142 /* handle message */
4143 ret = isotp_receive_flow_control_frame(link, &message, len);
4144
4145 if (ISOTP_RET_OK == ret) {
4146 /* refresh bs timer */
4147 link->send_timer_bs = isotp_user_get_us() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT_US;
4148
4149 /* overflow */
4150 if (PCI_FLOW_STATUS_OVERFLOW == message.as.flow_control.FS) {
4151 link->send_protocol_result = ISOTP_PROTOCOL_RESULT_BUFFER_OVFLW;
4152 link->send_status = ISOTP_SEND_STATUS_ERROR;
4153 }
4154
4155 /* wait */
4156 else if (PCI_FLOW_STATUS_WAIT == message.as.flow_control.FS) {
4157 link->send_wtf_count += 1;
4158 /* wait exceed allowed count */
4159 if (link->send_wtf_count > ISO_TP_MAX_WFT_NUMBER) {
4160 link->send_protocol_result = ISOTP_PROTOCOL_RESULT_WFT_OVRN;
4161 link->send_status = ISOTP_SEND_STATUS_ERROR;
4162 }
4163 }
4164
4165 /* permit send */
4166 else if (PCI_FLOW_STATUS_CONTINUE == message.as.flow_control.FS) {
4167 if (0 == message.as.flow_control.BS) {
4168 link->send_bs_remain = ISOTP_INVALID_BS;
4169 } else {
4170 link->send_bs_remain = message.as.flow_control.BS;
4171 }
4172 uint32_t message_st_min_us = isotp_st_min_to_us(message.as.flow_control.STmin);
4173 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?
4174 link->send_wtf_count = 0;
4175 }
4176 }
4177 break;
4178 default:
4179 break;
4180 };
4181
4182 return;
4183}
4184
4185int isotp_receive(IsoTpLink *link, uint8_t *payload, const uint16_t payload_size, uint16_t *out_size) {
4186 uint16_t copylen;
4187
4188 if (ISOTP_RECEIVE_STATUS_FULL != link->receive_status) {
4189 return ISOTP_RET_NO_DATA;
4190 }
4191
4192 copylen = link->receive_size;
4193 if (copylen > payload_size) {
4194 copylen = payload_size;
4195 }
4196
4197 memcpy(payload, link->receive_buffer, copylen);
4198 *out_size = copylen;
4199
4200 link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
4201
4202 return ISOTP_RET_OK;
4203}
4204
4205void isotp_init_link(IsoTpLink *link, uint32_t sendid, uint8_t *sendbuf, uint16_t sendbufsize, uint8_t *recvbuf, uint16_t recvbufsize) {
4206 memset(link, 0, sizeof(*link));
4207 link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
4208 link->send_status = ISOTP_SEND_STATUS_IDLE;
4209 link->send_arbitration_id = sendid;
4210 link->send_buffer = sendbuf;
4211 link->send_buf_size = sendbufsize;
4212 link->receive_buffer = recvbuf;
4213 link->receive_buf_size = recvbufsize;
4214
4215 return;
4216}
4217
4219 int ret;
4220
4221 /* only polling when operation in progress */
4222 if (ISOTP_SEND_STATUS_INPROGRESS == link->send_status) {
4223
4224 /* continue send data */
4225 if (/* send data if bs_remain is invalid or bs_remain large than zero */
4226 (ISOTP_INVALID_BS == link->send_bs_remain || link->send_bs_remain > 0) &&
4227 /* and if st_min is zero or go beyond interval time */
4228 (0 == link->send_st_min_us || IsoTpTimeAfter(isotp_user_get_us(), link->send_timer_st))) {
4229
4230 ret = isotp_send_consecutive_frame(link);
4231 if (ISOTP_RET_OK == ret) {
4232 if (ISOTP_INVALID_BS != link->send_bs_remain) {
4233 link->send_bs_remain -= 1;
4234 }
4235 link->send_timer_bs = isotp_user_get_us() + ISO_TP_DEFAULT_RESPONSE_TIMEOUT_US;
4236 link->send_timer_st = isotp_user_get_us() + link->send_st_min_us;
4237
4238 /* check if send finish */
4239 if (link->send_offset >= link->send_size) {
4240 link->send_status = ISOTP_SEND_STATUS_IDLE;
4241 }
4242 } else if (ISOTP_RET_NOSPACE == ret) {
4243 /* shim reported that it isn't able to send a frame at present, retry on next call */
4244 } else {
4245 link->send_status = ISOTP_SEND_STATUS_ERROR;
4246 }
4247 }
4248
4249 /* check timeout */
4250 if (IsoTpTimeAfter(isotp_user_get_us(), link->send_timer_bs)) {
4251 link->send_protocol_result = ISOTP_PROTOCOL_RESULT_TIMEOUT_BS;
4252 link->send_status = ISOTP_SEND_STATUS_ERROR;
4253 }
4254 }
4255
4256 /* only polling when operation in progress */
4257 if (ISOTP_RECEIVE_STATUS_INPROGRESS == link->receive_status) {
4258
4259 /* check timeout */
4260 if (IsoTpTimeAfter(isotp_user_get_us(), link->receive_timer_cr)) {
4261 link->receive_protocol_result = ISOTP_PROTOCOL_RESULT_TIMEOUT_CR;
4262 link->receive_status = ISOTP_RECEIVE_STATUS_IDLE;
4263 }
4264 }
4265
4266 return;
4267}
4268#endif
4269
bool UDSSecurityAccessLevelIsReserved(uint8_t subFunction)
Check if a security level is reserved per ISO14229-1:2020 Table 42.
Definition iso14229.c:2560
uint32_t isotp_user_get_us(void)
user implemented, gets the amount of time passed since the last call in microseconds
Definition iso14229.c:3029
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:3041
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:3660
uint32_t UDSMillis(void)
Get time in milliseconds.
Definition iso14229.c:2532
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:4185
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:4036
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:4205
void isotp_poll(IsoTpLink *link)
Polling function; call this function periodically to handle timeouts, send consecutive frames,...
Definition iso14229.c:4218
void ISOTPMockReset(void)
clear all transports and close the log file
Definition iso14229.c:3704
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:3983
int isotp_send(IsoTpLink *link, const uint8_t payload[], uint16_t size)
PUBLIC FUNCTIONS ///.
Definition iso14229.c:3979
void ISOTPMockLogToFile(const char *filename)
write all messages to a file
Definition iso14229.c:3680
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