Coverage Report

Created: 2026-10-17 06:35

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