1*84e33947SAndroid Build Coastguard Worker /*
2*84e33947SAndroid Build Coastguard Worker * Copyright (C) 2019 The Android Open Source Project
3*84e33947SAndroid Build Coastguard Worker *
4*84e33947SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*84e33947SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*84e33947SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*84e33947SAndroid Build Coastguard Worker *
8*84e33947SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*84e33947SAndroid Build Coastguard Worker *
10*84e33947SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*84e33947SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*84e33947SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*84e33947SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*84e33947SAndroid Build Coastguard Worker * limitations under the License.
15*84e33947SAndroid Build Coastguard Worker */
16*84e33947SAndroid Build Coastguard Worker
17*84e33947SAndroid Build Coastguard Worker #include "chpp/transport.h"
18*84e33947SAndroid Build Coastguard Worker
19*84e33947SAndroid Build Coastguard Worker #include <inttypes.h>
20*84e33947SAndroid Build Coastguard Worker #include <stdbool.h>
21*84e33947SAndroid Build Coastguard Worker #include <stddef.h>
22*84e33947SAndroid Build Coastguard Worker #include <stdint.h>
23*84e33947SAndroid Build Coastguard Worker #include <string.h>
24*84e33947SAndroid Build Coastguard Worker
25*84e33947SAndroid Build Coastguard Worker #include "chpp/app.h"
26*84e33947SAndroid Build Coastguard Worker #include "chpp/clients.h"
27*84e33947SAndroid Build Coastguard Worker #include "chpp/clients/discovery.h"
28*84e33947SAndroid Build Coastguard Worker #include "chpp/crc.h"
29*84e33947SAndroid Build Coastguard Worker #include "chpp/link.h"
30*84e33947SAndroid Build Coastguard Worker #include "chpp/log.h"
31*84e33947SAndroid Build Coastguard Worker #include "chpp/macros.h"
32*84e33947SAndroid Build Coastguard Worker #include "chpp/memory.h"
33*84e33947SAndroid Build Coastguard Worker #include "chpp/platform/platform_link.h"
34*84e33947SAndroid Build Coastguard Worker #include "chpp/services.h"
35*84e33947SAndroid Build Coastguard Worker #include "chpp/time.h"
36*84e33947SAndroid Build Coastguard Worker
37*84e33947SAndroid Build Coastguard Worker /************************************************
38*84e33947SAndroid Build Coastguard Worker * Prototypes
39*84e33947SAndroid Build Coastguard Worker ***********************************************/
40*84e33947SAndroid Build Coastguard Worker
41*84e33947SAndroid Build Coastguard Worker static void chppSetRxState(struct ChppTransportState *context,
42*84e33947SAndroid Build Coastguard Worker enum ChppRxState newState);
43*84e33947SAndroid Build Coastguard Worker static size_t chppConsumePreamble(struct ChppTransportState *context,
44*84e33947SAndroid Build Coastguard Worker const uint8_t *buf, size_t len);
45*84e33947SAndroid Build Coastguard Worker static size_t chppConsumeHeader(struct ChppTransportState *context,
46*84e33947SAndroid Build Coastguard Worker const uint8_t *buf, size_t len);
47*84e33947SAndroid Build Coastguard Worker static size_t chppConsumePayload(struct ChppTransportState *context,
48*84e33947SAndroid Build Coastguard Worker const uint8_t *buf, size_t len);
49*84e33947SAndroid Build Coastguard Worker static size_t chppConsumeFooter(struct ChppTransportState *context,
50*84e33947SAndroid Build Coastguard Worker const uint8_t *buf, size_t len);
51*84e33947SAndroid Build Coastguard Worker static void chppAbortRxPacket(struct ChppTransportState *context);
52*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_SERVICE_ENABLED_TRANSPORT_LOOPBACK
53*84e33947SAndroid Build Coastguard Worker static void chppProcessTransportLoopbackRequest(
54*84e33947SAndroid Build Coastguard Worker struct ChppTransportState *context);
55*84e33947SAndroid Build Coastguard Worker #endif
56*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_CLIENT_ENABLED_TRANSPORT_LOOPBACK
57*84e33947SAndroid Build Coastguard Worker static void chppProcessTransportLoopbackResponse(
58*84e33947SAndroid Build Coastguard Worker struct ChppTransportState *context);
59*84e33947SAndroid Build Coastguard Worker #endif
60*84e33947SAndroid Build Coastguard Worker static void chppSetResetComplete(struct ChppTransportState *context);
61*84e33947SAndroid Build Coastguard Worker static void chppProcessResetAck(struct ChppTransportState *context);
62*84e33947SAndroid Build Coastguard Worker static void chppProcessRxPacket(struct ChppTransportState *context);
63*84e33947SAndroid Build Coastguard Worker static void chppProcessRxPayload(struct ChppTransportState *context);
64*84e33947SAndroid Build Coastguard Worker static void chppClearRxDatagram(struct ChppTransportState *context);
65*84e33947SAndroid Build Coastguard Worker static bool chppRxChecksumIsOk(const struct ChppTransportState *context);
66*84e33947SAndroid Build Coastguard Worker static enum ChppTransportErrorCode chppRxHeaderCheck(
67*84e33947SAndroid Build Coastguard Worker const struct ChppTransportState *context);
68*84e33947SAndroid Build Coastguard Worker static void chppRegisterRxAck(struct ChppTransportState *context);
69*84e33947SAndroid Build Coastguard Worker
70*84e33947SAndroid Build Coastguard Worker static void chppEnqueueTxPacket(struct ChppTransportState *context,
71*84e33947SAndroid Build Coastguard Worker uint8_t packetCode);
72*84e33947SAndroid Build Coastguard Worker static size_t chppAddPreamble(uint8_t *buf);
73*84e33947SAndroid Build Coastguard Worker static struct ChppTransportHeader *chppAddHeader(
74*84e33947SAndroid Build Coastguard Worker struct ChppTransportState *context);
75*84e33947SAndroid Build Coastguard Worker static void chppAddPayload(struct ChppTransportState *context);
76*84e33947SAndroid Build Coastguard Worker static void chppAddFooter(struct ChppTransportState *context);
77*84e33947SAndroid Build Coastguard Worker // Can not be static (used in tests).
78*84e33947SAndroid Build Coastguard Worker size_t chppDequeueTxDatagram(struct ChppTransportState *context);
79*84e33947SAndroid Build Coastguard Worker static void chppClearTxDatagramQueue(struct ChppTransportState *context);
80*84e33947SAndroid Build Coastguard Worker static void chppTransportDoWork(struct ChppTransportState *context);
81*84e33947SAndroid Build Coastguard Worker static void chppAppendToPendingTxPacket(struct ChppTransportState *context,
82*84e33947SAndroid Build Coastguard Worker const uint8_t *buf, size_t len);
83*84e33947SAndroid Build Coastguard Worker static const char *chppGetPacketAttrStr(uint8_t packetCode);
84*84e33947SAndroid Build Coastguard Worker static bool chppEnqueueTxDatagram(struct ChppTransportState *context,
85*84e33947SAndroid Build Coastguard Worker uint8_t packetCode, void *buf, size_t len);
86*84e33947SAndroid Build Coastguard Worker static enum ChppLinkErrorCode chppSendPendingPacket(
87*84e33947SAndroid Build Coastguard Worker struct ChppTransportState *context);
88*84e33947SAndroid Build Coastguard Worker
89*84e33947SAndroid Build Coastguard Worker static void chppResetTransportContext(struct ChppTransportState *context);
90*84e33947SAndroid Build Coastguard Worker static void chppReset(struct ChppTransportState *context,
91*84e33947SAndroid Build Coastguard Worker enum ChppTransportPacketAttributes resetType,
92*84e33947SAndroid Build Coastguard Worker enum ChppTransportErrorCode error);
93*84e33947SAndroid Build Coastguard Worker struct ChppAppHeader *chppTransportGetRequestTimeoutResponse(
94*84e33947SAndroid Build Coastguard Worker struct ChppTransportState *context, enum ChppEndpointType type);
95*84e33947SAndroid Build Coastguard Worker static const char *chppGetRxStatusLabel(enum ChppRxState state);
96*84e33947SAndroid Build Coastguard Worker static void chppWorkHandleTimeout(struct ChppTransportState *context);
97*84e33947SAndroid Build Coastguard Worker
98*84e33947SAndroid Build Coastguard Worker /************************************************
99*84e33947SAndroid Build Coastguard Worker * Private Functions
100*84e33947SAndroid Build Coastguard Worker ***********************************************/
101*84e33947SAndroid Build Coastguard Worker
102*84e33947SAndroid Build Coastguard Worker /** Returns a string representation of the passed ChppRxState */
chppGetRxStatusLabel(enum ChppRxState state)103*84e33947SAndroid Build Coastguard Worker static const char *chppGetRxStatusLabel(enum ChppRxState state) {
104*84e33947SAndroid Build Coastguard Worker switch (state) {
105*84e33947SAndroid Build Coastguard Worker case CHPP_STATE_PREAMBLE:
106*84e33947SAndroid Build Coastguard Worker return "PREAMBLE (0)";
107*84e33947SAndroid Build Coastguard Worker case CHPP_STATE_HEADER:
108*84e33947SAndroid Build Coastguard Worker return "HEADER (1)";
109*84e33947SAndroid Build Coastguard Worker case CHPP_STATE_PAYLOAD:
110*84e33947SAndroid Build Coastguard Worker return "PAYLOAD (2)";
111*84e33947SAndroid Build Coastguard Worker case CHPP_STATE_FOOTER:
112*84e33947SAndroid Build Coastguard Worker return "FOOTER (3)";
113*84e33947SAndroid Build Coastguard Worker }
114*84e33947SAndroid Build Coastguard Worker
115*84e33947SAndroid Build Coastguard Worker return "invalid";
116*84e33947SAndroid Build Coastguard Worker }
117*84e33947SAndroid Build Coastguard Worker
118*84e33947SAndroid Build Coastguard Worker /**
119*84e33947SAndroid Build Coastguard Worker * Called any time the Rx state needs to be changed. Ensures that the location
120*84e33947SAndroid Build Coastguard Worker * counter among that state (rxStatus.locInState) is also reset at the same
121*84e33947SAndroid Build Coastguard Worker * time.
122*84e33947SAndroid Build Coastguard Worker *
123*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
124*84e33947SAndroid Build Coastguard Worker * @param newState Next Rx state.
125*84e33947SAndroid Build Coastguard Worker */
chppSetRxState(struct ChppTransportState * context,enum ChppRxState newState)126*84e33947SAndroid Build Coastguard Worker static void chppSetRxState(struct ChppTransportState *context,
127*84e33947SAndroid Build Coastguard Worker enum ChppRxState newState) {
128*84e33947SAndroid Build Coastguard Worker CHPP_LOGD(
129*84e33947SAndroid Build Coastguard Worker "Changing RX transport state from %s to %s"
130*84e33947SAndroid Build Coastguard Worker " after %" PRIuSIZE " bytes",
131*84e33947SAndroid Build Coastguard Worker chppGetRxStatusLabel(context->rxStatus.state),
132*84e33947SAndroid Build Coastguard Worker chppGetRxStatusLabel(newState), context->rxStatus.locInState);
133*84e33947SAndroid Build Coastguard Worker context->rxStatus.locInState = 0;
134*84e33947SAndroid Build Coastguard Worker context->rxStatus.state = newState;
135*84e33947SAndroid Build Coastguard Worker }
136*84e33947SAndroid Build Coastguard Worker
137*84e33947SAndroid Build Coastguard Worker /**
138*84e33947SAndroid Build Coastguard Worker * Called by chppRxDataCb to find a preamble (i.e. packet start delimiter) in
139*84e33947SAndroid Build Coastguard Worker * the incoming data stream.
140*84e33947SAndroid Build Coastguard Worker * Moves the state to CHPP_STATE_HEADER as soon as it has seen a complete
141*84e33947SAndroid Build Coastguard Worker * preamble.
142*84e33947SAndroid Build Coastguard Worker * Any future backwards-incompatible versions of CHPP Transport will use a
143*84e33947SAndroid Build Coastguard Worker * different preamble.
144*84e33947SAndroid Build Coastguard Worker *
145*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
146*84e33947SAndroid Build Coastguard Worker * @param buf Input data.
147*84e33947SAndroid Build Coastguard Worker * @param len Length of input data in bytes.
148*84e33947SAndroid Build Coastguard Worker *
149*84e33947SAndroid Build Coastguard Worker * @return Length of consumed data in bytes.
150*84e33947SAndroid Build Coastguard Worker */
chppConsumePreamble(struct ChppTransportState * context,const uint8_t * buf,size_t len)151*84e33947SAndroid Build Coastguard Worker static size_t chppConsumePreamble(struct ChppTransportState *context,
152*84e33947SAndroid Build Coastguard Worker const uint8_t *buf, size_t len) {
153*84e33947SAndroid Build Coastguard Worker size_t consumed = 0;
154*84e33947SAndroid Build Coastguard Worker
155*84e33947SAndroid Build Coastguard Worker // TODO: Optimize loop, maybe using memchr() / memcmp() / SIMD, especially if
156*84e33947SAndroid Build Coastguard Worker // serial port calling chppRxDataCb does not implement zero filter
157*84e33947SAndroid Build Coastguard Worker while (consumed < len &&
158*84e33947SAndroid Build Coastguard Worker context->rxStatus.locInState < CHPP_PREAMBLE_LEN_BYTES) {
159*84e33947SAndroid Build Coastguard Worker size_t offset = context->rxStatus.locInState;
160*84e33947SAndroid Build Coastguard Worker if ((offset == 0 && buf[consumed] == CHPP_PREAMBLE_BYTE_FIRST) ||
161*84e33947SAndroid Build Coastguard Worker (offset == 1 && buf[consumed] == CHPP_PREAMBLE_BYTE_SECOND)) {
162*84e33947SAndroid Build Coastguard Worker // Correct byte of preamble observed
163*84e33947SAndroid Build Coastguard Worker context->rxStatus.locInState++;
164*84e33947SAndroid Build Coastguard Worker
165*84e33947SAndroid Build Coastguard Worker } else if (buf[consumed] == CHPP_PREAMBLE_BYTE_FIRST) {
166*84e33947SAndroid Build Coastguard Worker // Previous search failed but first byte of another preamble observed
167*84e33947SAndroid Build Coastguard Worker context->rxStatus.locInState = 1;
168*84e33947SAndroid Build Coastguard Worker
169*84e33947SAndroid Build Coastguard Worker } else {
170*84e33947SAndroid Build Coastguard Worker // Continue search for a valid preamble from the start
171*84e33947SAndroid Build Coastguard Worker context->rxStatus.locInState = 0;
172*84e33947SAndroid Build Coastguard Worker }
173*84e33947SAndroid Build Coastguard Worker
174*84e33947SAndroid Build Coastguard Worker consumed++;
175*84e33947SAndroid Build Coastguard Worker }
176*84e33947SAndroid Build Coastguard Worker
177*84e33947SAndroid Build Coastguard Worker // Let's see why we exited the above loop
178*84e33947SAndroid Build Coastguard Worker if (context->rxStatus.locInState == CHPP_PREAMBLE_LEN_BYTES) {
179*84e33947SAndroid Build Coastguard Worker // Complete preamble observed, move on to next state
180*84e33947SAndroid Build Coastguard Worker context->rxStatus.packetStartTimeNs = chppGetCurrentTimeNs();
181*84e33947SAndroid Build Coastguard Worker chppSetRxState(context, CHPP_STATE_HEADER);
182*84e33947SAndroid Build Coastguard Worker }
183*84e33947SAndroid Build Coastguard Worker
184*84e33947SAndroid Build Coastguard Worker return consumed;
185*84e33947SAndroid Build Coastguard Worker }
186*84e33947SAndroid Build Coastguard Worker
187*84e33947SAndroid Build Coastguard Worker /**
188*84e33947SAndroid Build Coastguard Worker * Called by chppRxDataCb to process the packet header from the incoming data
189*84e33947SAndroid Build Coastguard Worker * stream.
190*84e33947SAndroid Build Coastguard Worker * Moves the Rx state to CHPP_STATE_PAYLOAD afterwards.
191*84e33947SAndroid Build Coastguard Worker *
192*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
193*84e33947SAndroid Build Coastguard Worker * @param buf Input data.
194*84e33947SAndroid Build Coastguard Worker * @param len Length of input data in bytes.
195*84e33947SAndroid Build Coastguard Worker *
196*84e33947SAndroid Build Coastguard Worker * @return Length of consumed data in bytes.
197*84e33947SAndroid Build Coastguard Worker */
chppConsumeHeader(struct ChppTransportState * context,const uint8_t * buf,size_t len)198*84e33947SAndroid Build Coastguard Worker static size_t chppConsumeHeader(struct ChppTransportState *context,
199*84e33947SAndroid Build Coastguard Worker const uint8_t *buf, size_t len) {
200*84e33947SAndroid Build Coastguard Worker CHPP_ASSERT(context->rxStatus.locInState <
201*84e33947SAndroid Build Coastguard Worker sizeof(struct ChppTransportHeader));
202*84e33947SAndroid Build Coastguard Worker size_t bytesToCopy = MIN(
203*84e33947SAndroid Build Coastguard Worker len, (sizeof(struct ChppTransportHeader) - context->rxStatus.locInState));
204*84e33947SAndroid Build Coastguard Worker memcpy(((uint8_t *)&context->rxHeader) + context->rxStatus.locInState, buf,
205*84e33947SAndroid Build Coastguard Worker bytesToCopy);
206*84e33947SAndroid Build Coastguard Worker context->rxStatus.locInState += bytesToCopy;
207*84e33947SAndroid Build Coastguard Worker
208*84e33947SAndroid Build Coastguard Worker if (context->rxStatus.locInState == sizeof(struct ChppTransportHeader)) {
209*84e33947SAndroid Build Coastguard Worker // Header fully copied. Move on
210*84e33947SAndroid Build Coastguard Worker
211*84e33947SAndroid Build Coastguard Worker enum ChppTransportErrorCode headerCheckResult = chppRxHeaderCheck(context);
212*84e33947SAndroid Build Coastguard Worker if (headerCheckResult != CHPP_TRANSPORT_ERROR_NONE) {
213*84e33947SAndroid Build Coastguard Worker // Header fails consistency check. NACK and return to preamble state
214*84e33947SAndroid Build Coastguard Worker chppEnqueueTxPacket(
215*84e33947SAndroid Build Coastguard Worker context, CHPP_ATTR_AND_ERROR_TO_PACKET_CODE(CHPP_TRANSPORT_ATTR_NONE,
216*84e33947SAndroid Build Coastguard Worker headerCheckResult));
217*84e33947SAndroid Build Coastguard Worker chppSetRxState(context, CHPP_STATE_PREAMBLE);
218*84e33947SAndroid Build Coastguard Worker
219*84e33947SAndroid Build Coastguard Worker } else if (context->rxHeader.length == 0) {
220*84e33947SAndroid Build Coastguard Worker // Non-payload packet
221*84e33947SAndroid Build Coastguard Worker chppSetRxState(context, CHPP_STATE_FOOTER);
222*84e33947SAndroid Build Coastguard Worker
223*84e33947SAndroid Build Coastguard Worker } else {
224*84e33947SAndroid Build Coastguard Worker // Payload bearing packet
225*84e33947SAndroid Build Coastguard Worker uint8_t *tempPayload;
226*84e33947SAndroid Build Coastguard Worker
227*84e33947SAndroid Build Coastguard Worker if (context->rxDatagram.length == 0) {
228*84e33947SAndroid Build Coastguard Worker // Packet is a new datagram
229*84e33947SAndroid Build Coastguard Worker tempPayload = chppMalloc(context->rxHeader.length);
230*84e33947SAndroid Build Coastguard Worker } else {
231*84e33947SAndroid Build Coastguard Worker // Packet is a continuation of a fragmented datagram
232*84e33947SAndroid Build Coastguard Worker tempPayload =
233*84e33947SAndroid Build Coastguard Worker chppRealloc(context->rxDatagram.payload,
234*84e33947SAndroid Build Coastguard Worker context->rxDatagram.length + context->rxHeader.length,
235*84e33947SAndroid Build Coastguard Worker context->rxDatagram.length);
236*84e33947SAndroid Build Coastguard Worker }
237*84e33947SAndroid Build Coastguard Worker
238*84e33947SAndroid Build Coastguard Worker if (tempPayload == NULL) {
239*84e33947SAndroid Build Coastguard Worker CHPP_LOG_OOM();
240*84e33947SAndroid Build Coastguard Worker chppEnqueueTxPacket(context, CHPP_TRANSPORT_ERROR_OOM);
241*84e33947SAndroid Build Coastguard Worker chppSetRxState(context, CHPP_STATE_PREAMBLE);
242*84e33947SAndroid Build Coastguard Worker } else {
243*84e33947SAndroid Build Coastguard Worker context->rxDatagram.payload = tempPayload;
244*84e33947SAndroid Build Coastguard Worker context->rxDatagram.length += context->rxHeader.length;
245*84e33947SAndroid Build Coastguard Worker chppSetRxState(context, CHPP_STATE_PAYLOAD);
246*84e33947SAndroid Build Coastguard Worker }
247*84e33947SAndroid Build Coastguard Worker }
248*84e33947SAndroid Build Coastguard Worker }
249*84e33947SAndroid Build Coastguard Worker
250*84e33947SAndroid Build Coastguard Worker return bytesToCopy;
251*84e33947SAndroid Build Coastguard Worker }
252*84e33947SAndroid Build Coastguard Worker
253*84e33947SAndroid Build Coastguard Worker /**
254*84e33947SAndroid Build Coastguard Worker * Called by chppRxDataCb to copy the payload, the length of which is determined
255*84e33947SAndroid Build Coastguard Worker * by the header, from the incoming data stream.
256*84e33947SAndroid Build Coastguard Worker * Moves the Rx state to CHPP_STATE_FOOTER afterwards.
257*84e33947SAndroid Build Coastguard Worker *
258*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
259*84e33947SAndroid Build Coastguard Worker * @param buf Input data
260*84e33947SAndroid Build Coastguard Worker * @param len Length of input data in bytes
261*84e33947SAndroid Build Coastguard Worker *
262*84e33947SAndroid Build Coastguard Worker * @return Length of consumed data in bytes
263*84e33947SAndroid Build Coastguard Worker */
chppConsumePayload(struct ChppTransportState * context,const uint8_t * buf,size_t len)264*84e33947SAndroid Build Coastguard Worker static size_t chppConsumePayload(struct ChppTransportState *context,
265*84e33947SAndroid Build Coastguard Worker const uint8_t *buf, size_t len) {
266*84e33947SAndroid Build Coastguard Worker CHPP_ASSERT(context->rxStatus.locInState < context->rxHeader.length);
267*84e33947SAndroid Build Coastguard Worker size_t bytesToCopy =
268*84e33947SAndroid Build Coastguard Worker MIN(len, (context->rxHeader.length - context->rxStatus.locInState));
269*84e33947SAndroid Build Coastguard Worker memcpy(context->rxDatagram.payload + context->rxStatus.locInDatagram, buf,
270*84e33947SAndroid Build Coastguard Worker bytesToCopy);
271*84e33947SAndroid Build Coastguard Worker context->rxStatus.locInDatagram += bytesToCopy;
272*84e33947SAndroid Build Coastguard Worker context->rxStatus.locInState += bytesToCopy;
273*84e33947SAndroid Build Coastguard Worker
274*84e33947SAndroid Build Coastguard Worker if (context->rxStatus.locInState == context->rxHeader.length) {
275*84e33947SAndroid Build Coastguard Worker // Entire packet payload copied. Move on
276*84e33947SAndroid Build Coastguard Worker chppSetRxState(context, CHPP_STATE_FOOTER);
277*84e33947SAndroid Build Coastguard Worker }
278*84e33947SAndroid Build Coastguard Worker
279*84e33947SAndroid Build Coastguard Worker return bytesToCopy;
280*84e33947SAndroid Build Coastguard Worker }
281*84e33947SAndroid Build Coastguard Worker
282*84e33947SAndroid Build Coastguard Worker /**
283*84e33947SAndroid Build Coastguard Worker * Called by chppRxDataCb to process the packet footer from the incoming data
284*84e33947SAndroid Build Coastguard Worker * stream. Checks checksum, triggering the correct response (ACK / NACK).
285*84e33947SAndroid Build Coastguard Worker * Moves the Rx state to CHPP_STATE_PREAMBLE afterwards.
286*84e33947SAndroid Build Coastguard Worker *
287*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
288*84e33947SAndroid Build Coastguard Worker * @param buf Input data.
289*84e33947SAndroid Build Coastguard Worker * @param len Length of input data in bytes.
290*84e33947SAndroid Build Coastguard Worker *
291*84e33947SAndroid Build Coastguard Worker * @return Length of consumed data in bytes.
292*84e33947SAndroid Build Coastguard Worker */
chppConsumeFooter(struct ChppTransportState * context,const uint8_t * buf,size_t len)293*84e33947SAndroid Build Coastguard Worker static size_t chppConsumeFooter(struct ChppTransportState *context,
294*84e33947SAndroid Build Coastguard Worker const uint8_t *buf, size_t len) {
295*84e33947SAndroid Build Coastguard Worker CHPP_ASSERT(context->rxStatus.locInState <
296*84e33947SAndroid Build Coastguard Worker sizeof(struct ChppTransportFooter));
297*84e33947SAndroid Build Coastguard Worker size_t bytesToCopy = MIN(
298*84e33947SAndroid Build Coastguard Worker len, (sizeof(struct ChppTransportFooter) - context->rxStatus.locInState));
299*84e33947SAndroid Build Coastguard Worker memcpy(((uint8_t *)&context->rxFooter) + context->rxStatus.locInState, buf,
300*84e33947SAndroid Build Coastguard Worker bytesToCopy);
301*84e33947SAndroid Build Coastguard Worker
302*84e33947SAndroid Build Coastguard Worker context->rxStatus.locInState += bytesToCopy;
303*84e33947SAndroid Build Coastguard Worker if (context->rxStatus.locInState == sizeof(struct ChppTransportFooter)) {
304*84e33947SAndroid Build Coastguard Worker // Footer copied. Move on
305*84e33947SAndroid Build Coastguard Worker
306*84e33947SAndroid Build Coastguard Worker if (CHPP_TRANSPORT_GET_ERROR(context->rxHeader.packetCode) !=
307*84e33947SAndroid Build Coastguard Worker CHPP_TRANSPORT_ERROR_NONE) {
308*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("RX packet len=%" PRIu16 " seq=%" PRIu8 " ackSeq=%" PRIu8
309*84e33947SAndroid Build Coastguard Worker " attr=0x%" PRIx8 " ERR=%" PRIu8 " flags=0x%" PRIx8,
310*84e33947SAndroid Build Coastguard Worker context->rxHeader.length, context->rxHeader.seq,
311*84e33947SAndroid Build Coastguard Worker context->rxHeader.ackSeq,
312*84e33947SAndroid Build Coastguard Worker (uint8_t)CHPP_TRANSPORT_GET_ATTR(context->rxHeader.packetCode),
313*84e33947SAndroid Build Coastguard Worker (uint8_t)CHPP_TRANSPORT_GET_ERROR(context->rxHeader.packetCode),
314*84e33947SAndroid Build Coastguard Worker context->rxHeader.flags);
315*84e33947SAndroid Build Coastguard Worker } else {
316*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("RX packet len=%" PRIu16 " seq=%" PRIu8 " ackSeq=%" PRIu8
317*84e33947SAndroid Build Coastguard Worker " attr=0x%" PRIx8 " err=%" PRIu8 " flags=0x%" PRIx8,
318*84e33947SAndroid Build Coastguard Worker context->rxHeader.length, context->rxHeader.seq,
319*84e33947SAndroid Build Coastguard Worker context->rxHeader.ackSeq,
320*84e33947SAndroid Build Coastguard Worker (uint8_t)CHPP_TRANSPORT_GET_ATTR(context->rxHeader.packetCode),
321*84e33947SAndroid Build Coastguard Worker (uint8_t)CHPP_TRANSPORT_GET_ERROR(context->rxHeader.packetCode),
322*84e33947SAndroid Build Coastguard Worker context->rxHeader.flags);
323*84e33947SAndroid Build Coastguard Worker }
324*84e33947SAndroid Build Coastguard Worker
325*84e33947SAndroid Build Coastguard Worker if (CHPP_TRANSPORT_GET_ATTR(context->rxHeader.packetCode) ==
326*84e33947SAndroid Build Coastguard Worker CHPP_TRANSPORT_ATTR_LOOPBACK_REQUEST) {
327*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_SERVICE_ENABLED_TRANSPORT_LOOPBACK
328*84e33947SAndroid Build Coastguard Worker chppProcessTransportLoopbackRequest(context);
329*84e33947SAndroid Build Coastguard Worker #endif
330*84e33947SAndroid Build Coastguard Worker
331*84e33947SAndroid Build Coastguard Worker } else if (CHPP_TRANSPORT_GET_ATTR(context->rxHeader.packetCode) ==
332*84e33947SAndroid Build Coastguard Worker CHPP_TRANSPORT_ATTR_LOOPBACK_RESPONSE) {
333*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_CLIENT_ENABLED_TRANSPORT_LOOPBACK
334*84e33947SAndroid Build Coastguard Worker chppProcessTransportLoopbackResponse(context);
335*84e33947SAndroid Build Coastguard Worker #endif
336*84e33947SAndroid Build Coastguard Worker
337*84e33947SAndroid Build Coastguard Worker } else if (!chppRxChecksumIsOk(context)) {
338*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Bad checksum seq=%" PRIu8 " len=%" PRIu16,
339*84e33947SAndroid Build Coastguard Worker context->rxHeader.seq, context->rxHeader.length);
340*84e33947SAndroid Build Coastguard Worker chppAbortRxPacket(context);
341*84e33947SAndroid Build Coastguard Worker chppEnqueueTxPacket(context, CHPP_TRANSPORT_ERROR_CHECKSUM); // NACK
342*84e33947SAndroid Build Coastguard Worker
343*84e33947SAndroid Build Coastguard Worker } else if (CHPP_TRANSPORT_GET_ATTR(context->rxHeader.packetCode) ==
344*84e33947SAndroid Build Coastguard Worker CHPP_TRANSPORT_ATTR_RESET) {
345*84e33947SAndroid Build Coastguard Worker CHPP_LOGI("RX RESET packet seq=%" PRIu8 " err=%" PRIu8,
346*84e33947SAndroid Build Coastguard Worker context->rxHeader.seq,
347*84e33947SAndroid Build Coastguard Worker CHPP_TRANSPORT_GET_ERROR(context->rxHeader.packetCode));
348*84e33947SAndroid Build Coastguard Worker chppMutexUnlock(&context->mutex);
349*84e33947SAndroid Build Coastguard Worker chppReset(context, CHPP_TRANSPORT_ATTR_RESET_ACK,
350*84e33947SAndroid Build Coastguard Worker CHPP_TRANSPORT_ERROR_NONE);
351*84e33947SAndroid Build Coastguard Worker chppMutexLock(&context->mutex);
352*84e33947SAndroid Build Coastguard Worker
353*84e33947SAndroid Build Coastguard Worker } else if (context->resetState == CHPP_RESET_STATE_PERMANENT_FAILURE) {
354*84e33947SAndroid Build Coastguard Worker // Only a reset is accepted in this state
355*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("RX discarded in perm fail seq=%" PRIu8 " len=%" PRIu16,
356*84e33947SAndroid Build Coastguard Worker context->rxHeader.seq, context->rxHeader.length);
357*84e33947SAndroid Build Coastguard Worker chppAbortRxPacket(context);
358*84e33947SAndroid Build Coastguard Worker
359*84e33947SAndroid Build Coastguard Worker } else if (CHPP_TRANSPORT_GET_ATTR(context->rxHeader.packetCode) ==
360*84e33947SAndroid Build Coastguard Worker CHPP_TRANSPORT_ATTR_RESET_ACK) {
361*84e33947SAndroid Build Coastguard Worker CHPP_LOGI("RX RESET-ACK packet seq=%" PRIu8, context->rxHeader.seq);
362*84e33947SAndroid Build Coastguard Worker chppProcessResetAck(context);
363*84e33947SAndroid Build Coastguard Worker
364*84e33947SAndroid Build Coastguard Worker } else if (context->resetState == CHPP_RESET_STATE_RESETTING) {
365*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("RX discarded in reset seq=%" PRIu8 " len=%" PRIu16,
366*84e33947SAndroid Build Coastguard Worker context->rxHeader.seq, context->rxHeader.length);
367*84e33947SAndroid Build Coastguard Worker chppAbortRxPacket(context);
368*84e33947SAndroid Build Coastguard Worker
369*84e33947SAndroid Build Coastguard Worker } else {
370*84e33947SAndroid Build Coastguard Worker chppProcessRxPacket(context);
371*84e33947SAndroid Build Coastguard Worker }
372*84e33947SAndroid Build Coastguard Worker
373*84e33947SAndroid Build Coastguard Worker // Done with this packet. Wait for next packet
374*84e33947SAndroid Build Coastguard Worker chppSetRxState(context, CHPP_STATE_PREAMBLE);
375*84e33947SAndroid Build Coastguard Worker }
376*84e33947SAndroid Build Coastguard Worker
377*84e33947SAndroid Build Coastguard Worker return bytesToCopy;
378*84e33947SAndroid Build Coastguard Worker }
379*84e33947SAndroid Build Coastguard Worker
380*84e33947SAndroid Build Coastguard Worker /**
381*84e33947SAndroid Build Coastguard Worker * Discards of an incomplete Rx packet during receive (e.g. due to a timeout or
382*84e33947SAndroid Build Coastguard Worker * bad checksum).
383*84e33947SAndroid Build Coastguard Worker *
384*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
385*84e33947SAndroid Build Coastguard Worker */
chppAbortRxPacket(struct ChppTransportState * context)386*84e33947SAndroid Build Coastguard Worker static void chppAbortRxPacket(struct ChppTransportState *context) {
387*84e33947SAndroid Build Coastguard Worker size_t undoLen = 0;
388*84e33947SAndroid Build Coastguard Worker size_t undoLoc = 0;
389*84e33947SAndroid Build Coastguard Worker
390*84e33947SAndroid Build Coastguard Worker switch (context->rxStatus.state) {
391*84e33947SAndroid Build Coastguard Worker case (CHPP_STATE_PREAMBLE):
392*84e33947SAndroid Build Coastguard Worker case (CHPP_STATE_HEADER): {
393*84e33947SAndroid Build Coastguard Worker break;
394*84e33947SAndroid Build Coastguard Worker }
395*84e33947SAndroid Build Coastguard Worker
396*84e33947SAndroid Build Coastguard Worker case (CHPP_STATE_PAYLOAD): {
397*84e33947SAndroid Build Coastguard Worker undoLen = context->rxHeader.length;
398*84e33947SAndroid Build Coastguard Worker undoLoc = context->rxStatus.locInState;
399*84e33947SAndroid Build Coastguard Worker break;
400*84e33947SAndroid Build Coastguard Worker }
401*84e33947SAndroid Build Coastguard Worker
402*84e33947SAndroid Build Coastguard Worker case (CHPP_STATE_FOOTER): {
403*84e33947SAndroid Build Coastguard Worker undoLen = context->rxHeader.length;
404*84e33947SAndroid Build Coastguard Worker undoLoc = context->rxHeader.length;
405*84e33947SAndroid Build Coastguard Worker break;
406*84e33947SAndroid Build Coastguard Worker }
407*84e33947SAndroid Build Coastguard Worker
408*84e33947SAndroid Build Coastguard Worker default: {
409*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_ASSERT(false);
410*84e33947SAndroid Build Coastguard Worker }
411*84e33947SAndroid Build Coastguard Worker }
412*84e33947SAndroid Build Coastguard Worker
413*84e33947SAndroid Build Coastguard Worker if (undoLen > 0) {
414*84e33947SAndroid Build Coastguard Worker // Packet has a payload we need to discard of
415*84e33947SAndroid Build Coastguard Worker
416*84e33947SAndroid Build Coastguard Worker CHPP_ASSERT(context->rxDatagram.length >= undoLen);
417*84e33947SAndroid Build Coastguard Worker CHPP_ASSERT(context->rxStatus.locInDatagram >= undoLoc);
418*84e33947SAndroid Build Coastguard Worker context->rxDatagram.length -= undoLen;
419*84e33947SAndroid Build Coastguard Worker context->rxStatus.locInDatagram -= undoLoc;
420*84e33947SAndroid Build Coastguard Worker
421*84e33947SAndroid Build Coastguard Worker if (context->rxDatagram.length == 0) {
422*84e33947SAndroid Build Coastguard Worker // Discarding this packet == discarding entire datagram
423*84e33947SAndroid Build Coastguard Worker CHPP_FREE_AND_NULLIFY(context->rxDatagram.payload);
424*84e33947SAndroid Build Coastguard Worker
425*84e33947SAndroid Build Coastguard Worker } else {
426*84e33947SAndroid Build Coastguard Worker // Discarding this packet == discarding part of datagram
427*84e33947SAndroid Build Coastguard Worker uint8_t *tempPayload =
428*84e33947SAndroid Build Coastguard Worker chppRealloc(context->rxDatagram.payload, context->rxDatagram.length,
429*84e33947SAndroid Build Coastguard Worker context->rxDatagram.length + undoLen);
430*84e33947SAndroid Build Coastguard Worker
431*84e33947SAndroid Build Coastguard Worker if (tempPayload == NULL) {
432*84e33947SAndroid Build Coastguard Worker CHPP_LOG_OOM();
433*84e33947SAndroid Build Coastguard Worker } else {
434*84e33947SAndroid Build Coastguard Worker context->rxDatagram.payload = tempPayload;
435*84e33947SAndroid Build Coastguard Worker }
436*84e33947SAndroid Build Coastguard Worker }
437*84e33947SAndroid Build Coastguard Worker }
438*84e33947SAndroid Build Coastguard Worker
439*84e33947SAndroid Build Coastguard Worker chppSetRxState(context, CHPP_STATE_PREAMBLE);
440*84e33947SAndroid Build Coastguard Worker }
441*84e33947SAndroid Build Coastguard Worker
442*84e33947SAndroid Build Coastguard Worker /**
443*84e33947SAndroid Build Coastguard Worker * Processes a request that is determined to be for a transport-layer loopback.
444*84e33947SAndroid Build Coastguard Worker *
445*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
446*84e33947SAndroid Build Coastguard Worker */
447*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_SERVICE_ENABLED_TRANSPORT_LOOPBACK
chppProcessTransportLoopbackRequest(struct ChppTransportState * context)448*84e33947SAndroid Build Coastguard Worker static void chppProcessTransportLoopbackRequest(
449*84e33947SAndroid Build Coastguard Worker struct ChppTransportState *context) {
450*84e33947SAndroid Build Coastguard Worker if (context->txStatus.linkBusy) {
451*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Link busy; trans-loopback dropped");
452*84e33947SAndroid Build Coastguard Worker
453*84e33947SAndroid Build Coastguard Worker } else {
454*84e33947SAndroid Build Coastguard Worker uint8_t *linkTxBuffer = context->linkApi->getTxBuffer(context->linkContext);
455*84e33947SAndroid Build Coastguard Worker context->txStatus.linkBusy = true;
456*84e33947SAndroid Build Coastguard Worker context->linkBufferSize = 0;
457*84e33947SAndroid Build Coastguard Worker context->linkBufferSize += chppAddPreamble(&linkTxBuffer[0]);
458*84e33947SAndroid Build Coastguard Worker
459*84e33947SAndroid Build Coastguard Worker struct ChppTransportHeader *txHeader =
460*84e33947SAndroid Build Coastguard Worker (struct ChppTransportHeader *)&linkTxBuffer[context->linkBufferSize];
461*84e33947SAndroid Build Coastguard Worker context->linkBufferSize += sizeof(*txHeader);
462*84e33947SAndroid Build Coastguard Worker
463*84e33947SAndroid Build Coastguard Worker *txHeader = context->rxHeader;
464*84e33947SAndroid Build Coastguard Worker txHeader->packetCode = CHPP_ATTR_AND_ERROR_TO_PACKET_CODE(
465*84e33947SAndroid Build Coastguard Worker CHPP_TRANSPORT_ATTR_LOOPBACK_RESPONSE, txHeader->packetCode);
466*84e33947SAndroid Build Coastguard Worker
467*84e33947SAndroid Build Coastguard Worker size_t payloadLen =
468*84e33947SAndroid Build Coastguard Worker MIN(context->rxDatagram.length, chppTransportTxMtuSize(context));
469*84e33947SAndroid Build Coastguard Worker chppAppendToPendingTxPacket(context, context->rxDatagram.payload,
470*84e33947SAndroid Build Coastguard Worker payloadLen);
471*84e33947SAndroid Build Coastguard Worker CHPP_FREE_AND_NULLIFY(context->rxDatagram.payload);
472*84e33947SAndroid Build Coastguard Worker chppClearRxDatagram(context);
473*84e33947SAndroid Build Coastguard Worker
474*84e33947SAndroid Build Coastguard Worker chppAddFooter(context);
475*84e33947SAndroid Build Coastguard Worker
476*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("Trans-looping back len=%" PRIu16 " RX len=%" PRIuSIZE,
477*84e33947SAndroid Build Coastguard Worker txHeader->length, context->rxDatagram.length);
478*84e33947SAndroid Build Coastguard Worker enum ChppLinkErrorCode error = chppSendPendingPacket(context);
479*84e33947SAndroid Build Coastguard Worker
480*84e33947SAndroid Build Coastguard Worker if (error != CHPP_LINK_ERROR_NONE_QUEUED) {
481*84e33947SAndroid Build Coastguard Worker chppLinkSendDoneCb(context, error);
482*84e33947SAndroid Build Coastguard Worker }
483*84e33947SAndroid Build Coastguard Worker }
484*84e33947SAndroid Build Coastguard Worker }
485*84e33947SAndroid Build Coastguard Worker #endif
486*84e33947SAndroid Build Coastguard Worker
487*84e33947SAndroid Build Coastguard Worker /**
488*84e33947SAndroid Build Coastguard Worker * Processes a response that is determined to be for a transport-layer loopback.
489*84e33947SAndroid Build Coastguard Worker *
490*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
491*84e33947SAndroid Build Coastguard Worker */
492*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_CLIENT_ENABLED_TRANSPORT_LOOPBACK
chppProcessTransportLoopbackResponse(struct ChppTransportState * context)493*84e33947SAndroid Build Coastguard Worker static void chppProcessTransportLoopbackResponse(
494*84e33947SAndroid Build Coastguard Worker struct ChppTransportState *context) {
495*84e33947SAndroid Build Coastguard Worker if (context->transportLoopbackData.length != context->rxDatagram.length) {
496*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("RX len=%" PRIuSIZE " != TX len=%" PRIuSIZE,
497*84e33947SAndroid Build Coastguard Worker context->rxDatagram.length,
498*84e33947SAndroid Build Coastguard Worker context->transportLoopbackData.length - CHPP_PREAMBLE_LEN_BYTES -
499*84e33947SAndroid Build Coastguard Worker sizeof(struct ChppTransportHeader) -
500*84e33947SAndroid Build Coastguard Worker sizeof(struct ChppTransportFooter));
501*84e33947SAndroid Build Coastguard Worker context->loopbackResult = CHPP_APP_ERROR_INVALID_LENGTH;
502*84e33947SAndroid Build Coastguard Worker
503*84e33947SAndroid Build Coastguard Worker } else if (memcmp(context->rxDatagram.payload,
504*84e33947SAndroid Build Coastguard Worker context->transportLoopbackData.payload,
505*84e33947SAndroid Build Coastguard Worker context->rxDatagram.length) != 0) {
506*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("RX & TX data don't match: len=%" PRIuSIZE,
507*84e33947SAndroid Build Coastguard Worker context->rxDatagram.length);
508*84e33947SAndroid Build Coastguard Worker context->loopbackResult = CHPP_APP_ERROR_INVALID_ARG;
509*84e33947SAndroid Build Coastguard Worker
510*84e33947SAndroid Build Coastguard Worker } else {
511*84e33947SAndroid Build Coastguard Worker context->loopbackResult = CHPP_APP_ERROR_NONE;
512*84e33947SAndroid Build Coastguard Worker
513*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("RX successful transport-loopback (payload len=%" PRIuSIZE ")",
514*84e33947SAndroid Build Coastguard Worker context->rxDatagram.length);
515*84e33947SAndroid Build Coastguard Worker }
516*84e33947SAndroid Build Coastguard Worker
517*84e33947SAndroid Build Coastguard Worker context->transportLoopbackData.length = 0;
518*84e33947SAndroid Build Coastguard Worker CHPP_FREE_AND_NULLIFY(context->transportLoopbackData.payload);
519*84e33947SAndroid Build Coastguard Worker CHPP_FREE_AND_NULLIFY(context->rxDatagram.payload);
520*84e33947SAndroid Build Coastguard Worker chppClearRxDatagram(context);
521*84e33947SAndroid Build Coastguard Worker }
522*84e33947SAndroid Build Coastguard Worker #endif
523*84e33947SAndroid Build Coastguard Worker
524*84e33947SAndroid Build Coastguard Worker /**
525*84e33947SAndroid Build Coastguard Worker * Method to invoke when the reset sequence is completed.
526*84e33947SAndroid Build Coastguard Worker *
527*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
528*84e33947SAndroid Build Coastguard Worker */
chppSetResetComplete(struct ChppTransportState * context)529*84e33947SAndroid Build Coastguard Worker static void chppSetResetComplete(struct ChppTransportState *context) {
530*84e33947SAndroid Build Coastguard Worker context->resetState = CHPP_RESET_STATE_NONE;
531*84e33947SAndroid Build Coastguard Worker context->resetCount = 0;
532*84e33947SAndroid Build Coastguard Worker chppConditionVariableSignal(&context->resetCondVar);
533*84e33947SAndroid Build Coastguard Worker }
534*84e33947SAndroid Build Coastguard Worker
535*84e33947SAndroid Build Coastguard Worker /**
536*84e33947SAndroid Build Coastguard Worker * An incoming reset-ack packet indicates that a reset is complete at the other
537*84e33947SAndroid Build Coastguard Worker * end of the CHPP link.
538*84e33947SAndroid Build Coastguard Worker *
539*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
540*84e33947SAndroid Build Coastguard Worker */
chppProcessResetAck(struct ChppTransportState * context)541*84e33947SAndroid Build Coastguard Worker static void chppProcessResetAck(struct ChppTransportState *context) {
542*84e33947SAndroid Build Coastguard Worker if (context->resetState == CHPP_RESET_STATE_NONE) {
543*84e33947SAndroid Build Coastguard Worker CHPP_LOGW("Unexpected reset-ack seq=%" PRIu8 " code=0x%" PRIx8,
544*84e33947SAndroid Build Coastguard Worker context->rxHeader.seq, context->rxHeader.packetCode);
545*84e33947SAndroid Build Coastguard Worker // In a reset race condition with both endpoints sending resets and
546*84e33947SAndroid Build Coastguard Worker // reset-acks, the sent resets and reset-acks will both have a sequence
547*84e33947SAndroid Build Coastguard Worker // number of 0.
548*84e33947SAndroid Build Coastguard Worker // By ignoring the received reset-ack, the next expected sequence number
549*84e33947SAndroid Build Coastguard Worker // will remain at 1 (following a reset with a sequence number of 0).
550*84e33947SAndroid Build Coastguard Worker // Therefore, no further correction is necessary (beyond ignoring the
551*84e33947SAndroid Build Coastguard Worker // received reset-ack), as the next packet (e.g. discovery) will have a
552*84e33947SAndroid Build Coastguard Worker // sequence number of 1.
553*84e33947SAndroid Build Coastguard Worker
554*84e33947SAndroid Build Coastguard Worker chppDatagramProcessDoneCb(context, context->rxDatagram.payload);
555*84e33947SAndroid Build Coastguard Worker chppClearRxDatagram(context);
556*84e33947SAndroid Build Coastguard Worker
557*84e33947SAndroid Build Coastguard Worker return;
558*84e33947SAndroid Build Coastguard Worker }
559*84e33947SAndroid Build Coastguard Worker
560*84e33947SAndroid Build Coastguard Worker chppSetResetComplete(context);
561*84e33947SAndroid Build Coastguard Worker context->rxStatus.receivedPacketCode = context->rxHeader.packetCode;
562*84e33947SAndroid Build Coastguard Worker context->rxStatus.expectedSeq = context->rxHeader.seq + 1;
563*84e33947SAndroid Build Coastguard Worker chppRegisterRxAck(context);
564*84e33947SAndroid Build Coastguard Worker
565*84e33947SAndroid Build Coastguard Worker // TODO: Configure transport layer based on (optional?) received config
566*84e33947SAndroid Build Coastguard Worker
567*84e33947SAndroid Build Coastguard Worker chppDatagramProcessDoneCb(context, context->rxDatagram.payload);
568*84e33947SAndroid Build Coastguard Worker chppClearRxDatagram(context);
569*84e33947SAndroid Build Coastguard Worker
570*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_CLIENT_ENABLED_DISCOVERY
571*84e33947SAndroid Build Coastguard Worker if (context->appContext->isDiscoveryComplete) {
572*84e33947SAndroid Build Coastguard Worker chppEnqueueTxPacket(context, CHPP_TRANSPORT_ERROR_NONE);
573*84e33947SAndroid Build Coastguard Worker }
574*84e33947SAndroid Build Coastguard Worker #else
575*84e33947SAndroid Build Coastguard Worker chppEnqueueTxPacket(context, CHPP_TRANSPORT_ERROR_NONE);
576*84e33947SAndroid Build Coastguard Worker #endif
577*84e33947SAndroid Build Coastguard Worker
578*84e33947SAndroid Build Coastguard Worker // Inform the App Layer that a reset has completed
579*84e33947SAndroid Build Coastguard Worker chppMutexUnlock(&context->mutex);
580*84e33947SAndroid Build Coastguard Worker chppAppProcessReset(context->appContext);
581*84e33947SAndroid Build Coastguard Worker chppMutexLock(&context->mutex);
582*84e33947SAndroid Build Coastguard Worker }
583*84e33947SAndroid Build Coastguard Worker
584*84e33947SAndroid Build Coastguard Worker /**
585*84e33947SAndroid Build Coastguard Worker * Process a received, checksum-validated packet.
586*84e33947SAndroid Build Coastguard Worker *
587*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
588*84e33947SAndroid Build Coastguard Worker */
chppProcessRxPacket(struct ChppTransportState * context)589*84e33947SAndroid Build Coastguard Worker static void chppProcessRxPacket(struct ChppTransportState *context) {
590*84e33947SAndroid Build Coastguard Worker uint64_t now = chppGetCurrentTimeNs();
591*84e33947SAndroid Build Coastguard Worker context->rxStatus.lastGoodPacketTimeMs = (uint32_t)(now / CHPP_NSEC_PER_MSEC);
592*84e33947SAndroid Build Coastguard Worker context->rxStatus.receivedPacketCode = context->rxHeader.packetCode;
593*84e33947SAndroid Build Coastguard Worker chppRegisterRxAck(context);
594*84e33947SAndroid Build Coastguard Worker
595*84e33947SAndroid Build Coastguard Worker enum ChppTransportErrorCode errorCode = CHPP_TRANSPORT_ERROR_NONE;
596*84e33947SAndroid Build Coastguard Worker if (context->rxHeader.length > 0 &&
597*84e33947SAndroid Build Coastguard Worker context->rxHeader.seq != context->rxStatus.expectedSeq) {
598*84e33947SAndroid Build Coastguard Worker // Out of order payload
599*84e33947SAndroid Build Coastguard Worker errorCode = CHPP_TRANSPORT_ERROR_ORDER;
600*84e33947SAndroid Build Coastguard Worker }
601*84e33947SAndroid Build Coastguard Worker
602*84e33947SAndroid Build Coastguard Worker if (context->txDatagramQueue.pending > 0 ||
603*84e33947SAndroid Build Coastguard Worker errorCode == CHPP_TRANSPORT_ERROR_ORDER) {
604*84e33947SAndroid Build Coastguard Worker // There are packets to send out (could be new or retx)
605*84e33947SAndroid Build Coastguard Worker // Note: For a future ACK window > 1, makes more sense to cap the NACKs
606*84e33947SAndroid Build Coastguard Worker // to one instead of flooding with out of order NACK errors.
607*84e33947SAndroid Build Coastguard Worker
608*84e33947SAndroid Build Coastguard Worker // If the sender is retrying a packet we've already received successfully,
609*84e33947SAndroid Build Coastguard Worker // send an ACK so it will continue normally
610*84e33947SAndroid Build Coastguard Worker enum ChppTransportErrorCode errorCodeToSend = errorCode;
611*84e33947SAndroid Build Coastguard Worker if (context->rxHeader.length > 0 &&
612*84e33947SAndroid Build Coastguard Worker context->rxHeader.seq == context->rxStatus.expectedSeq - 1) {
613*84e33947SAndroid Build Coastguard Worker errorCodeToSend = CHPP_TRANSPORT_ERROR_NONE;
614*84e33947SAndroid Build Coastguard Worker }
615*84e33947SAndroid Build Coastguard Worker
616*84e33947SAndroid Build Coastguard Worker chppEnqueueTxPacket(
617*84e33947SAndroid Build Coastguard Worker context, CHPP_ATTR_AND_ERROR_TO_PACKET_CODE(CHPP_TRANSPORT_ATTR_NONE,
618*84e33947SAndroid Build Coastguard Worker errorCodeToSend));
619*84e33947SAndroid Build Coastguard Worker }
620*84e33947SAndroid Build Coastguard Worker
621*84e33947SAndroid Build Coastguard Worker if (errorCode == CHPP_TRANSPORT_ERROR_ORDER) {
622*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Out of order RX discarded seq=%" PRIu8 " expect=%" PRIu8
623*84e33947SAndroid Build Coastguard Worker " len=%" PRIu16,
624*84e33947SAndroid Build Coastguard Worker context->rxHeader.seq, context->rxStatus.expectedSeq,
625*84e33947SAndroid Build Coastguard Worker context->rxHeader.length);
626*84e33947SAndroid Build Coastguard Worker chppAbortRxPacket(context);
627*84e33947SAndroid Build Coastguard Worker
628*84e33947SAndroid Build Coastguard Worker } else if (context->rxHeader.length > 0) {
629*84e33947SAndroid Build Coastguard Worker // Process payload and send ACK
630*84e33947SAndroid Build Coastguard Worker chppProcessRxPayload(context);
631*84e33947SAndroid Build Coastguard Worker } else if (!context->txStatus.hasPacketsToSend) {
632*84e33947SAndroid Build Coastguard Worker // Nothing to send and nothing to receive, i.e. this is an ACK before an
633*84e33947SAndroid Build Coastguard Worker // indefinite period of inactivity. Kick the work thread so it recalculates
634*84e33947SAndroid Build Coastguard Worker // the notifier timeout.
635*84e33947SAndroid Build Coastguard Worker chppNotifierSignal(&context->notifier,
636*84e33947SAndroid Build Coastguard Worker CHPP_TRANSPORT_SIGNAL_RECALC_TIMEOUT);
637*84e33947SAndroid Build Coastguard Worker }
638*84e33947SAndroid Build Coastguard Worker }
639*84e33947SAndroid Build Coastguard Worker
640*84e33947SAndroid Build Coastguard Worker /**
641*84e33947SAndroid Build Coastguard Worker * Process the payload of a validated payload-bearing packet and send out the
642*84e33947SAndroid Build Coastguard Worker * ACK.
643*84e33947SAndroid Build Coastguard Worker *
644*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
645*84e33947SAndroid Build Coastguard Worker */
chppProcessRxPayload(struct ChppTransportState * context)646*84e33947SAndroid Build Coastguard Worker static void chppProcessRxPayload(struct ChppTransportState *context) {
647*84e33947SAndroid Build Coastguard Worker context->rxStatus.expectedSeq++; // chppProcessRxPacket() already confirms
648*84e33947SAndroid Build Coastguard Worker // that context->rxStatus.expectedSeq ==
649*84e33947SAndroid Build Coastguard Worker // context->rxHeader.seq, protecting against
650*84e33947SAndroid Build Coastguard Worker // duplicate and out-of-order packets.
651*84e33947SAndroid Build Coastguard Worker
652*84e33947SAndroid Build Coastguard Worker if (context->rxHeader.flags & CHPP_TRANSPORT_FLAG_UNFINISHED_DATAGRAM) {
653*84e33947SAndroid Build Coastguard Worker // Packet is part of a larger datagram
654*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("RX packet for unfinished datagram. Seq=%" PRIu8 " len=%" PRIu16
655*84e33947SAndroid Build Coastguard Worker ". Datagram len=%" PRIuSIZE ". Sending ACK=%" PRIu8,
656*84e33947SAndroid Build Coastguard Worker context->rxHeader.seq, context->rxHeader.length,
657*84e33947SAndroid Build Coastguard Worker context->rxDatagram.length, context->rxStatus.expectedSeq);
658*84e33947SAndroid Build Coastguard Worker
659*84e33947SAndroid Build Coastguard Worker } else {
660*84e33947SAndroid Build Coastguard Worker // End of this packet is end of a datagram
661*84e33947SAndroid Build Coastguard Worker
662*84e33947SAndroid Build Coastguard Worker // Send the payload to the App Layer
663*84e33947SAndroid Build Coastguard Worker // Note that it is up to the app layer to free the buffer using
664*84e33947SAndroid Build Coastguard Worker // chppDatagramProcessDoneCb() after is is done.
665*84e33947SAndroid Build Coastguard Worker chppMutexUnlock(&context->mutex);
666*84e33947SAndroid Build Coastguard Worker chppAppProcessRxDatagram(context->appContext, context->rxDatagram.payload,
667*84e33947SAndroid Build Coastguard Worker context->rxDatagram.length);
668*84e33947SAndroid Build Coastguard Worker chppMutexLock(&context->mutex);
669*84e33947SAndroid Build Coastguard Worker
670*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("App layer processed datagram with len=%" PRIuSIZE
671*84e33947SAndroid Build Coastguard Worker ", ending packet seq=%" PRIu8 ", len=%" PRIu16
672*84e33947SAndroid Build Coastguard Worker ". Sending ACK=%" PRIu8 " (previously sent=%" PRIu8 ")",
673*84e33947SAndroid Build Coastguard Worker context->rxDatagram.length, context->rxHeader.seq,
674*84e33947SAndroid Build Coastguard Worker context->rxHeader.length, context->rxStatus.expectedSeq,
675*84e33947SAndroid Build Coastguard Worker context->txStatus.sentAckSeq);
676*84e33947SAndroid Build Coastguard Worker chppClearRxDatagram(context);
677*84e33947SAndroid Build Coastguard Worker }
678*84e33947SAndroid Build Coastguard Worker
679*84e33947SAndroid Build Coastguard Worker // Send ACK because we had RX a payload-bearing packet
680*84e33947SAndroid Build Coastguard Worker chppEnqueueTxPacket(context, CHPP_TRANSPORT_ERROR_NONE);
681*84e33947SAndroid Build Coastguard Worker }
682*84e33947SAndroid Build Coastguard Worker
683*84e33947SAndroid Build Coastguard Worker /**
684*84e33947SAndroid Build Coastguard Worker * Resets the incoming datagram state, i.e. after the datagram has been
685*84e33947SAndroid Build Coastguard Worker * processed.
686*84e33947SAndroid Build Coastguard Worker * Note that this is independent from freeing the payload. It is up to the app
687*84e33947SAndroid Build Coastguard Worker * layer to inform the transport layer using chppDatagramProcessDoneCb() once it
688*84e33947SAndroid Build Coastguard Worker * is done with the buffer so it is freed.
689*84e33947SAndroid Build Coastguard Worker *
690*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
691*84e33947SAndroid Build Coastguard Worker */
chppClearRxDatagram(struct ChppTransportState * context)692*84e33947SAndroid Build Coastguard Worker static void chppClearRxDatagram(struct ChppTransportState *context) {
693*84e33947SAndroid Build Coastguard Worker context->rxStatus.locInDatagram = 0;
694*84e33947SAndroid Build Coastguard Worker context->rxDatagram.length = 0;
695*84e33947SAndroid Build Coastguard Worker context->rxDatagram.payload = NULL;
696*84e33947SAndroid Build Coastguard Worker }
697*84e33947SAndroid Build Coastguard Worker
698*84e33947SAndroid Build Coastguard Worker /**
699*84e33947SAndroid Build Coastguard Worker * Validates the checksum of an incoming packet.
700*84e33947SAndroid Build Coastguard Worker *
701*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
702*84e33947SAndroid Build Coastguard Worker *
703*84e33947SAndroid Build Coastguard Worker * @return True if and only if the checksum is correct.
704*84e33947SAndroid Build Coastguard Worker */
chppRxChecksumIsOk(const struct ChppTransportState * context)705*84e33947SAndroid Build Coastguard Worker static bool chppRxChecksumIsOk(const struct ChppTransportState *context) {
706*84e33947SAndroid Build Coastguard Worker uint32_t crc = chppCrc32(0, (const uint8_t *)&context->rxHeader,
707*84e33947SAndroid Build Coastguard Worker sizeof(context->rxHeader));
708*84e33947SAndroid Build Coastguard Worker crc = chppCrc32(
709*84e33947SAndroid Build Coastguard Worker crc,
710*84e33947SAndroid Build Coastguard Worker &context->rxDatagram
711*84e33947SAndroid Build Coastguard Worker .payload[context->rxStatus.locInDatagram - context->rxHeader.length],
712*84e33947SAndroid Build Coastguard Worker context->rxHeader.length);
713*84e33947SAndroid Build Coastguard Worker
714*84e33947SAndroid Build Coastguard Worker if (context->rxFooter.checksum != crc) {
715*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("RX BAD checksum: footer=0x%" PRIx32 ", calc=0x%" PRIx32
716*84e33947SAndroid Build Coastguard Worker ", len=%" PRIuSIZE,
717*84e33947SAndroid Build Coastguard Worker context->rxFooter.checksum, crc,
718*84e33947SAndroid Build Coastguard Worker (size_t)(context->rxHeader.length +
719*84e33947SAndroid Build Coastguard Worker sizeof(struct ChppTransportHeader)));
720*84e33947SAndroid Build Coastguard Worker }
721*84e33947SAndroid Build Coastguard Worker
722*84e33947SAndroid Build Coastguard Worker return (context->rxFooter.checksum == crc);
723*84e33947SAndroid Build Coastguard Worker }
724*84e33947SAndroid Build Coastguard Worker
725*84e33947SAndroid Build Coastguard Worker /**
726*84e33947SAndroid Build Coastguard Worker * Performs consistency checks on received packet header to determine if it is
727*84e33947SAndroid Build Coastguard Worker * obviously corrupt / invalid / duplicate / out-of-order.
728*84e33947SAndroid Build Coastguard Worker *
729*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
730*84e33947SAndroid Build Coastguard Worker *
731*84e33947SAndroid Build Coastguard Worker * @return True if and only if header passes checks
732*84e33947SAndroid Build Coastguard Worker */
chppRxHeaderCheck(const struct ChppTransportState * context)733*84e33947SAndroid Build Coastguard Worker static enum ChppTransportErrorCode chppRxHeaderCheck(
734*84e33947SAndroid Build Coastguard Worker const struct ChppTransportState *context) {
735*84e33947SAndroid Build Coastguard Worker enum ChppTransportErrorCode result = CHPP_TRANSPORT_ERROR_NONE;
736*84e33947SAndroid Build Coastguard Worker
737*84e33947SAndroid Build Coastguard Worker if (context->rxHeader.length > chppTransportRxMtuSize(context)) {
738*84e33947SAndroid Build Coastguard Worker result = CHPP_TRANSPORT_ERROR_HEADER;
739*84e33947SAndroid Build Coastguard Worker }
740*84e33947SAndroid Build Coastguard Worker
741*84e33947SAndroid Build Coastguard Worker if (result != CHPP_TRANSPORT_ERROR_NONE) {
742*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Bad header. seq=%" PRIu8 " expect=%" PRIu8 " len=%" PRIu16
743*84e33947SAndroid Build Coastguard Worker " err=%" PRIu8,
744*84e33947SAndroid Build Coastguard Worker context->rxHeader.seq, context->rxStatus.expectedSeq,
745*84e33947SAndroid Build Coastguard Worker context->rxHeader.length, result);
746*84e33947SAndroid Build Coastguard Worker }
747*84e33947SAndroid Build Coastguard Worker
748*84e33947SAndroid Build Coastguard Worker return result;
749*84e33947SAndroid Build Coastguard Worker }
750*84e33947SAndroid Build Coastguard Worker
751*84e33947SAndroid Build Coastguard Worker /**
752*84e33947SAndroid Build Coastguard Worker * Registers a received ACK. If an outgoing datagram is fully ACKed, it is
753*84e33947SAndroid Build Coastguard Worker * popped from the TX queue.
754*84e33947SAndroid Build Coastguard Worker *
755*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
756*84e33947SAndroid Build Coastguard Worker */
chppRegisterRxAck(struct ChppTransportState * context)757*84e33947SAndroid Build Coastguard Worker static void chppRegisterRxAck(struct ChppTransportState *context) {
758*84e33947SAndroid Build Coastguard Worker uint8_t rxAckSeq = context->rxHeader.ackSeq;
759*84e33947SAndroid Build Coastguard Worker
760*84e33947SAndroid Build Coastguard Worker if (context->rxStatus.receivedAckSeq != rxAckSeq) {
761*84e33947SAndroid Build Coastguard Worker // A previously sent packet was actually ACKed
762*84e33947SAndroid Build Coastguard Worker // Note: For a future ACK window >1, we should loop by # of ACKed packets
763*84e33947SAndroid Build Coastguard Worker if ((uint8_t)(context->rxStatus.receivedAckSeq + 1) != rxAckSeq) {
764*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Out of order ACK: last=%" PRIu8 " rx=%" PRIu8,
765*84e33947SAndroid Build Coastguard Worker context->rxStatus.receivedAckSeq, rxAckSeq);
766*84e33947SAndroid Build Coastguard Worker } else {
767*84e33947SAndroid Build Coastguard Worker CHPP_LOGD(
768*84e33947SAndroid Build Coastguard Worker "ACK received (last registered=%" PRIu8 ", received=%" PRIu8
769*84e33947SAndroid Build Coastguard Worker "). Prior queue depth=%" PRIu8 ", front datagram=%" PRIu8
770*84e33947SAndroid Build Coastguard Worker " at loc=%" PRIuSIZE " of len=%" PRIuSIZE,
771*84e33947SAndroid Build Coastguard Worker context->rxStatus.receivedAckSeq, rxAckSeq,
772*84e33947SAndroid Build Coastguard Worker context->txDatagramQueue.pending, context->txDatagramQueue.front,
773*84e33947SAndroid Build Coastguard Worker context->txStatus.ackedLocInDatagram,
774*84e33947SAndroid Build Coastguard Worker context->txDatagramQueue.datagram[context->txDatagramQueue.front]
775*84e33947SAndroid Build Coastguard Worker .length);
776*84e33947SAndroid Build Coastguard Worker
777*84e33947SAndroid Build Coastguard Worker context->rxStatus.receivedAckSeq = rxAckSeq;
778*84e33947SAndroid Build Coastguard Worker if (context->txStatus.txAttempts > 1) {
779*84e33947SAndroid Build Coastguard Worker CHPP_LOGW("Seq %" PRIu8 " ACK'd after %" PRIuSIZE " reTX",
780*84e33947SAndroid Build Coastguard Worker context->rxHeader.ackSeq - 1,
781*84e33947SAndroid Build Coastguard Worker context->txStatus.txAttempts - 1);
782*84e33947SAndroid Build Coastguard Worker }
783*84e33947SAndroid Build Coastguard Worker context->txStatus.txAttempts = 0;
784*84e33947SAndroid Build Coastguard Worker
785*84e33947SAndroid Build Coastguard Worker // Process and if necessary pop from Tx datagram queue
786*84e33947SAndroid Build Coastguard Worker context->txStatus.ackedLocInDatagram += chppTransportTxMtuSize(context);
787*84e33947SAndroid Build Coastguard Worker if (context->txStatus.ackedLocInDatagram >=
788*84e33947SAndroid Build Coastguard Worker context->txDatagramQueue.datagram[context->txDatagramQueue.front]
789*84e33947SAndroid Build Coastguard Worker .length) {
790*84e33947SAndroid Build Coastguard Worker // We are done with datagram
791*84e33947SAndroid Build Coastguard Worker
792*84e33947SAndroid Build Coastguard Worker context->txStatus.ackedLocInDatagram = 0;
793*84e33947SAndroid Build Coastguard Worker context->txStatus.sentLocInDatagram = 0;
794*84e33947SAndroid Build Coastguard Worker
795*84e33947SAndroid Build Coastguard Worker // Note: For a future ACK window >1, we need to update the queue
796*84e33947SAndroid Build Coastguard Worker // position of the datagram being sent as well (relative to the
797*84e33947SAndroid Build Coastguard Worker // front-of-queue). e.g. context->txStatus.datagramBeingSent--;
798*84e33947SAndroid Build Coastguard Worker
799*84e33947SAndroid Build Coastguard Worker if (chppDequeueTxDatagram(context) == 0) {
800*84e33947SAndroid Build Coastguard Worker context->txStatus.hasPacketsToSend = false;
801*84e33947SAndroid Build Coastguard Worker }
802*84e33947SAndroid Build Coastguard Worker }
803*84e33947SAndroid Build Coastguard Worker }
804*84e33947SAndroid Build Coastguard Worker } // else {nothing was ACKed}
805*84e33947SAndroid Build Coastguard Worker }
806*84e33947SAndroid Build Coastguard Worker
807*84e33947SAndroid Build Coastguard Worker /**
808*84e33947SAndroid Build Coastguard Worker * Enqueues an outgoing packet with the specified error code. The error code
809*84e33947SAndroid Build Coastguard Worker * refers to the optional reason behind a NACK, if any. An error code of
810*84e33947SAndroid Build Coastguard Worker * CHPP_TRANSPORT_ERROR_NONE indicates that no error was reported (i.e. either
811*84e33947SAndroid Build Coastguard Worker * an ACK or an implicit NACK)
812*84e33947SAndroid Build Coastguard Worker *
813*84e33947SAndroid Build Coastguard Worker * Note that the decision as to whether to include a payload will be taken
814*84e33947SAndroid Build Coastguard Worker * later, i.e. before the packet is being sent out from the queue. A payload is
815*84e33947SAndroid Build Coastguard Worker * expected to be included if there is one or more pending Tx datagrams and we
816*84e33947SAndroid Build Coastguard Worker * are not waiting on a pending ACK. A (repeat) payload is also included if we
817*84e33947SAndroid Build Coastguard Worker * have received a NACK.
818*84e33947SAndroid Build Coastguard Worker *
819*84e33947SAndroid Build Coastguard Worker * Further note that even for systems with an ACK window greater than one, we
820*84e33947SAndroid Build Coastguard Worker * would only need to send an ACK for the last (correct) packet, hence we only
821*84e33947SAndroid Build Coastguard Worker * need a queue length of one here.
822*84e33947SAndroid Build Coastguard Worker *
823*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
824*84e33947SAndroid Build Coastguard Worker * @param packetCode Error code and packet attributes to be sent.
825*84e33947SAndroid Build Coastguard Worker */
chppEnqueueTxPacket(struct ChppTransportState * context,uint8_t packetCode)826*84e33947SAndroid Build Coastguard Worker static void chppEnqueueTxPacket(struct ChppTransportState *context,
827*84e33947SAndroid Build Coastguard Worker uint8_t packetCode) {
828*84e33947SAndroid Build Coastguard Worker context->txStatus.hasPacketsToSend = true;
829*84e33947SAndroid Build Coastguard Worker context->txStatus.packetCodeToSend = packetCode;
830*84e33947SAndroid Build Coastguard Worker
831*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("chppEnqueueTxPacket called with packet code=0x%" PRIx8,
832*84e33947SAndroid Build Coastguard Worker packetCode);
833*84e33947SAndroid Build Coastguard Worker
834*84e33947SAndroid Build Coastguard Worker // Notifies the main CHPP Transport Layer to run chppTransportDoWork().
835*84e33947SAndroid Build Coastguard Worker chppNotifierSignal(&context->notifier, CHPP_TRANSPORT_SIGNAL_EVENT);
836*84e33947SAndroid Build Coastguard Worker }
837*84e33947SAndroid Build Coastguard Worker
838*84e33947SAndroid Build Coastguard Worker /**
839*84e33947SAndroid Build Coastguard Worker * Adds a CHPP preamble to the beginning of buf.
840*84e33947SAndroid Build Coastguard Worker *
841*84e33947SAndroid Build Coastguard Worker * @param buf The CHPP preamble will be added to buf.
842*84e33947SAndroid Build Coastguard Worker *
843*84e33947SAndroid Build Coastguard Worker * @return Size of the added preamble.
844*84e33947SAndroid Build Coastguard Worker */
chppAddPreamble(uint8_t * buf)845*84e33947SAndroid Build Coastguard Worker static size_t chppAddPreamble(uint8_t *buf) {
846*84e33947SAndroid Build Coastguard Worker buf[0] = CHPP_PREAMBLE_BYTE_FIRST;
847*84e33947SAndroid Build Coastguard Worker buf[1] = CHPP_PREAMBLE_BYTE_SECOND;
848*84e33947SAndroid Build Coastguard Worker return CHPP_PREAMBLE_LEN_BYTES;
849*84e33947SAndroid Build Coastguard Worker }
850*84e33947SAndroid Build Coastguard Worker
851*84e33947SAndroid Build Coastguard Worker /**
852*84e33947SAndroid Build Coastguard Worker * Adds the packet header to link tx buffer.
853*84e33947SAndroid Build Coastguard Worker *
854*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
855*84e33947SAndroid Build Coastguard Worker *
856*84e33947SAndroid Build Coastguard Worker * @return Pointer to the added packet header.
857*84e33947SAndroid Build Coastguard Worker */
chppAddHeader(struct ChppTransportState * context)858*84e33947SAndroid Build Coastguard Worker static struct ChppTransportHeader *chppAddHeader(
859*84e33947SAndroid Build Coastguard Worker struct ChppTransportState *context) {
860*84e33947SAndroid Build Coastguard Worker uint8_t *linkTxBuffer = context->linkApi->getTxBuffer(context->linkContext);
861*84e33947SAndroid Build Coastguard Worker struct ChppTransportHeader *txHeader =
862*84e33947SAndroid Build Coastguard Worker (struct ChppTransportHeader *)&linkTxBuffer[context->linkBufferSize];
863*84e33947SAndroid Build Coastguard Worker context->linkBufferSize += sizeof(*txHeader);
864*84e33947SAndroid Build Coastguard Worker
865*84e33947SAndroid Build Coastguard Worker txHeader->packetCode = context->txStatus.packetCodeToSend;
866*84e33947SAndroid Build Coastguard Worker context->txStatus.packetCodeToSend = CHPP_ATTR_AND_ERROR_TO_PACKET_CODE(
867*84e33947SAndroid Build Coastguard Worker context->txStatus.packetCodeToSend, CHPP_TRANSPORT_ERROR_NONE);
868*84e33947SAndroid Build Coastguard Worker
869*84e33947SAndroid Build Coastguard Worker txHeader->ackSeq = context->rxStatus.expectedSeq;
870*84e33947SAndroid Build Coastguard Worker context->txStatus.sentAckSeq = txHeader->ackSeq;
871*84e33947SAndroid Build Coastguard Worker
872*84e33947SAndroid Build Coastguard Worker return txHeader;
873*84e33947SAndroid Build Coastguard Worker }
874*84e33947SAndroid Build Coastguard Worker
875*84e33947SAndroid Build Coastguard Worker /**
876*84e33947SAndroid Build Coastguard Worker * Adds the packet payload to link tx buffer.
877*84e33947SAndroid Build Coastguard Worker *
878*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
879*84e33947SAndroid Build Coastguard Worker */
chppAddPayload(struct ChppTransportState * context)880*84e33947SAndroid Build Coastguard Worker static void chppAddPayload(struct ChppTransportState *context) {
881*84e33947SAndroid Build Coastguard Worker uint8_t *linkTxBuffer = context->linkApi->getTxBuffer(context->linkContext);
882*84e33947SAndroid Build Coastguard Worker struct ChppTransportHeader *txHeader =
883*84e33947SAndroid Build Coastguard Worker (struct ChppTransportHeader *)&linkTxBuffer[CHPP_PREAMBLE_LEN_BYTES];
884*84e33947SAndroid Build Coastguard Worker
885*84e33947SAndroid Build Coastguard Worker size_t remainingBytes =
886*84e33947SAndroid Build Coastguard Worker context->txDatagramQueue.datagram[context->txDatagramQueue.front].length -
887*84e33947SAndroid Build Coastguard Worker context->txStatus.ackedLocInDatagram;
888*84e33947SAndroid Build Coastguard Worker
889*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("Adding payload to seq=%" PRIu8 ", remainingBytes=%" PRIuSIZE
890*84e33947SAndroid Build Coastguard Worker " of pending datagrams=%" PRIu8,
891*84e33947SAndroid Build Coastguard Worker txHeader->seq, remainingBytes, context->txDatagramQueue.pending);
892*84e33947SAndroid Build Coastguard Worker
893*84e33947SAndroid Build Coastguard Worker if (remainingBytes > chppTransportTxMtuSize(context)) {
894*84e33947SAndroid Build Coastguard Worker // Send an unfinished part of a datagram
895*84e33947SAndroid Build Coastguard Worker txHeader->flags = CHPP_TRANSPORT_FLAG_UNFINISHED_DATAGRAM;
896*84e33947SAndroid Build Coastguard Worker txHeader->length = (uint16_t)chppTransportTxMtuSize(context);
897*84e33947SAndroid Build Coastguard Worker } else {
898*84e33947SAndroid Build Coastguard Worker // Send final (or only) part of a datagram
899*84e33947SAndroid Build Coastguard Worker txHeader->flags = CHPP_TRANSPORT_FLAG_FINISHED_DATAGRAM;
900*84e33947SAndroid Build Coastguard Worker txHeader->length = (uint16_t)remainingBytes;
901*84e33947SAndroid Build Coastguard Worker }
902*84e33947SAndroid Build Coastguard Worker
903*84e33947SAndroid Build Coastguard Worker // Copy payload
904*84e33947SAndroid Build Coastguard Worker chppAppendToPendingTxPacket(
905*84e33947SAndroid Build Coastguard Worker context,
906*84e33947SAndroid Build Coastguard Worker context->txDatagramQueue.datagram[context->txDatagramQueue.front]
907*84e33947SAndroid Build Coastguard Worker .payload +
908*84e33947SAndroid Build Coastguard Worker context->txStatus.ackedLocInDatagram,
909*84e33947SAndroid Build Coastguard Worker txHeader->length);
910*84e33947SAndroid Build Coastguard Worker
911*84e33947SAndroid Build Coastguard Worker context->txStatus.sentLocInDatagram =
912*84e33947SAndroid Build Coastguard Worker context->txStatus.ackedLocInDatagram + txHeader->length;
913*84e33947SAndroid Build Coastguard Worker }
914*84e33947SAndroid Build Coastguard Worker
915*84e33947SAndroid Build Coastguard Worker /**
916*84e33947SAndroid Build Coastguard Worker * Adds a footer (containing the checksum) to a packet.
917*84e33947SAndroid Build Coastguard Worker *
918*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
919*84e33947SAndroid Build Coastguard Worker */
chppAddFooter(struct ChppTransportState * context)920*84e33947SAndroid Build Coastguard Worker static void chppAddFooter(struct ChppTransportState *context) {
921*84e33947SAndroid Build Coastguard Worker struct ChppTransportFooter footer;
922*84e33947SAndroid Build Coastguard Worker uint8_t *linkTxBuffer = context->linkApi->getTxBuffer(context->linkContext);
923*84e33947SAndroid Build Coastguard Worker size_t bufferSize = context->linkBufferSize;
924*84e33947SAndroid Build Coastguard Worker
925*84e33947SAndroid Build Coastguard Worker footer.checksum = chppCrc32(0, &linkTxBuffer[CHPP_PREAMBLE_LEN_BYTES],
926*84e33947SAndroid Build Coastguard Worker bufferSize - CHPP_PREAMBLE_LEN_BYTES);
927*84e33947SAndroid Build Coastguard Worker
928*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("Adding transport footer. Checksum=0x%" PRIx32 ", len: %" PRIuSIZE
929*84e33947SAndroid Build Coastguard Worker " -> %" PRIuSIZE,
930*84e33947SAndroid Build Coastguard Worker footer.checksum, bufferSize, bufferSize + sizeof(footer));
931*84e33947SAndroid Build Coastguard Worker
932*84e33947SAndroid Build Coastguard Worker chppAppendToPendingTxPacket(context, (const uint8_t *)&footer,
933*84e33947SAndroid Build Coastguard Worker sizeof(footer));
934*84e33947SAndroid Build Coastguard Worker }
935*84e33947SAndroid Build Coastguard Worker
936*84e33947SAndroid Build Coastguard Worker /**
937*84e33947SAndroid Build Coastguard Worker * Dequeues the datagram at the front of the datagram tx queue, if any, and
938*84e33947SAndroid Build Coastguard Worker * frees the payload. Returns the number of remaining datagrams in the queue.
939*84e33947SAndroid Build Coastguard Worker *
940*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
941*84e33947SAndroid Build Coastguard Worker * @return Number of remaining datagrams in queue.
942*84e33947SAndroid Build Coastguard Worker */
chppDequeueTxDatagram(struct ChppTransportState * context)943*84e33947SAndroid Build Coastguard Worker size_t chppDequeueTxDatagram(struct ChppTransportState *context) {
944*84e33947SAndroid Build Coastguard Worker if (context->txDatagramQueue.pending == 0) {
945*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Can not dequeue empty datagram queue");
946*84e33947SAndroid Build Coastguard Worker
947*84e33947SAndroid Build Coastguard Worker } else {
948*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("Dequeuing front datagram with index=%" PRIu8 ", len=%" PRIuSIZE
949*84e33947SAndroid Build Coastguard Worker ". Queue depth: %" PRIu8 "->%d",
950*84e33947SAndroid Build Coastguard Worker context->txDatagramQueue.front,
951*84e33947SAndroid Build Coastguard Worker context->txDatagramQueue.datagram[context->txDatagramQueue.front]
952*84e33947SAndroid Build Coastguard Worker .length,
953*84e33947SAndroid Build Coastguard Worker context->txDatagramQueue.pending,
954*84e33947SAndroid Build Coastguard Worker context->txDatagramQueue.pending - 1);
955*84e33947SAndroid Build Coastguard Worker
956*84e33947SAndroid Build Coastguard Worker CHPP_FREE_AND_NULLIFY(
957*84e33947SAndroid Build Coastguard Worker context->txDatagramQueue.datagram[context->txDatagramQueue.front]
958*84e33947SAndroid Build Coastguard Worker .payload);
959*84e33947SAndroid Build Coastguard Worker context->txDatagramQueue.datagram[context->txDatagramQueue.front].length =
960*84e33947SAndroid Build Coastguard Worker 0;
961*84e33947SAndroid Build Coastguard Worker
962*84e33947SAndroid Build Coastguard Worker context->txDatagramQueue.pending--;
963*84e33947SAndroid Build Coastguard Worker context->txDatagramQueue.front++;
964*84e33947SAndroid Build Coastguard Worker context->txDatagramQueue.front %= CHPP_TX_DATAGRAM_QUEUE_LEN;
965*84e33947SAndroid Build Coastguard Worker }
966*84e33947SAndroid Build Coastguard Worker
967*84e33947SAndroid Build Coastguard Worker return context->txDatagramQueue.pending;
968*84e33947SAndroid Build Coastguard Worker }
969*84e33947SAndroid Build Coastguard Worker
970*84e33947SAndroid Build Coastguard Worker /**
971*84e33947SAndroid Build Coastguard Worker * Flushes the Tx datagram queue of any pending packets.
972*84e33947SAndroid Build Coastguard Worker *
973*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
974*84e33947SAndroid Build Coastguard Worker */
chppClearTxDatagramQueue(struct ChppTransportState * context)975*84e33947SAndroid Build Coastguard Worker static void chppClearTxDatagramQueue(struct ChppTransportState *context) {
976*84e33947SAndroid Build Coastguard Worker while (context->txDatagramQueue.pending > 0) {
977*84e33947SAndroid Build Coastguard Worker chppDequeueTxDatagram(context);
978*84e33947SAndroid Build Coastguard Worker }
979*84e33947SAndroid Build Coastguard Worker context->txStatus.hasPacketsToSend = false;
980*84e33947SAndroid Build Coastguard Worker }
981*84e33947SAndroid Build Coastguard Worker
982*84e33947SAndroid Build Coastguard Worker /**
983*84e33947SAndroid Build Coastguard Worker * Sends out a pending outgoing packet based on a notification from
984*84e33947SAndroid Build Coastguard Worker * chppEnqueueTxPacket().
985*84e33947SAndroid Build Coastguard Worker *
986*84e33947SAndroid Build Coastguard Worker * A payload may or may not be included be according the following:
987*84e33947SAndroid Build Coastguard Worker * No payload: If Tx datagram queue is empty OR we are waiting on a pending ACK.
988*84e33947SAndroid Build Coastguard Worker * New payload: If there is one or more pending Tx datagrams and we are not
989*84e33947SAndroid Build Coastguard Worker * waiting on a pending ACK.
990*84e33947SAndroid Build Coastguard Worker * Repeat payload: If we haven't received an ACK yet for our previous payload,
991*84e33947SAndroid Build Coastguard Worker * i.e. we have registered an explicit or implicit NACK.
992*84e33947SAndroid Build Coastguard Worker *
993*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
994*84e33947SAndroid Build Coastguard Worker */
chppTransportDoWork(struct ChppTransportState * context)995*84e33947SAndroid Build Coastguard Worker static void chppTransportDoWork(struct ChppTransportState *context) {
996*84e33947SAndroid Build Coastguard Worker bool havePacketForLinkLayer = false;
997*84e33947SAndroid Build Coastguard Worker struct ChppTransportHeader *txHeader;
998*84e33947SAndroid Build Coastguard Worker
999*84e33947SAndroid Build Coastguard Worker // Note: For a future ACK window >1, there needs to be a loop outside the lock
1000*84e33947SAndroid Build Coastguard Worker chppMutexLock(&context->mutex);
1001*84e33947SAndroid Build Coastguard Worker
1002*84e33947SAndroid Build Coastguard Worker if (context->txStatus.hasPacketsToSend && !context->txStatus.linkBusy) {
1003*84e33947SAndroid Build Coastguard Worker // There are pending outgoing packets and the link isn't busy
1004*84e33947SAndroid Build Coastguard Worker havePacketForLinkLayer = true;
1005*84e33947SAndroid Build Coastguard Worker context->txStatus.linkBusy = true;
1006*84e33947SAndroid Build Coastguard Worker
1007*84e33947SAndroid Build Coastguard Worker context->linkBufferSize = 0;
1008*84e33947SAndroid Build Coastguard Worker uint8_t *linkTxBuffer = context->linkApi->getTxBuffer(context->linkContext);
1009*84e33947SAndroid Build Coastguard Worker const struct ChppLinkConfiguration linkConfig =
1010*84e33947SAndroid Build Coastguard Worker context->linkApi->getConfig(context->linkContext);
1011*84e33947SAndroid Build Coastguard Worker memset(linkTxBuffer, 0, linkConfig.txBufferLen);
1012*84e33947SAndroid Build Coastguard Worker
1013*84e33947SAndroid Build Coastguard Worker // Add preamble
1014*84e33947SAndroid Build Coastguard Worker context->linkBufferSize += chppAddPreamble(linkTxBuffer);
1015*84e33947SAndroid Build Coastguard Worker
1016*84e33947SAndroid Build Coastguard Worker // Add header
1017*84e33947SAndroid Build Coastguard Worker txHeader = chppAddHeader(context);
1018*84e33947SAndroid Build Coastguard Worker
1019*84e33947SAndroid Build Coastguard Worker // If applicable, add payload
1020*84e33947SAndroid Build Coastguard Worker if ((context->txDatagramQueue.pending > 0)) {
1021*84e33947SAndroid Build Coastguard Worker // Note: For a future ACK window >1, we need to rewrite this payload
1022*84e33947SAndroid Build Coastguard Worker // adding code to base the next packet on the sent location within the
1023*84e33947SAndroid Build Coastguard Worker // last sent datagram, except for the case of a NACK (explicit or
1024*84e33947SAndroid Build Coastguard Worker // timeout). For a NACK, we would need to base the next packet off the
1025*84e33947SAndroid Build Coastguard Worker // last ACKed location.
1026*84e33947SAndroid Build Coastguard Worker
1027*84e33947SAndroid Build Coastguard Worker txHeader->seq = context->rxStatus.receivedAckSeq;
1028*84e33947SAndroid Build Coastguard Worker context->txStatus.sentSeq = txHeader->seq;
1029*84e33947SAndroid Build Coastguard Worker
1030*84e33947SAndroid Build Coastguard Worker if (context->txStatus.txAttempts > CHPP_TRANSPORT_MAX_RETX &&
1031*84e33947SAndroid Build Coastguard Worker context->resetState != CHPP_RESET_STATE_RESETTING) {
1032*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Resetting after %d reTX", CHPP_TRANSPORT_MAX_RETX);
1033*84e33947SAndroid Build Coastguard Worker havePacketForLinkLayer = false;
1034*84e33947SAndroid Build Coastguard Worker
1035*84e33947SAndroid Build Coastguard Worker chppMutexUnlock(&context->mutex);
1036*84e33947SAndroid Build Coastguard Worker chppReset(context, CHPP_TRANSPORT_ATTR_RESET,
1037*84e33947SAndroid Build Coastguard Worker CHPP_TRANSPORT_ERROR_MAX_RETRIES);
1038*84e33947SAndroid Build Coastguard Worker chppMutexLock(&context->mutex);
1039*84e33947SAndroid Build Coastguard Worker
1040*84e33947SAndroid Build Coastguard Worker } else {
1041*84e33947SAndroid Build Coastguard Worker chppAddPayload(context);
1042*84e33947SAndroid Build Coastguard Worker context->txStatus.txAttempts++;
1043*84e33947SAndroid Build Coastguard Worker }
1044*84e33947SAndroid Build Coastguard Worker
1045*84e33947SAndroid Build Coastguard Worker } else {
1046*84e33947SAndroid Build Coastguard Worker // No payload
1047*84e33947SAndroid Build Coastguard Worker context->txStatus.hasPacketsToSend = false;
1048*84e33947SAndroid Build Coastguard Worker }
1049*84e33947SAndroid Build Coastguard Worker
1050*84e33947SAndroid Build Coastguard Worker chppAddFooter(context);
1051*84e33947SAndroid Build Coastguard Worker
1052*84e33947SAndroid Build Coastguard Worker } else {
1053*84e33947SAndroid Build Coastguard Worker CHPP_LOGW(
1054*84e33947SAndroid Build Coastguard Worker "DoWork nothing to send. hasPackets=%d, linkBusy=%d, pending=%" PRIu8
1055*84e33947SAndroid Build Coastguard Worker ", RX ACK=%" PRIu8 ", TX seq=%" PRIu8 ", RX state=%s",
1056*84e33947SAndroid Build Coastguard Worker context->txStatus.hasPacketsToSend, context->txStatus.linkBusy,
1057*84e33947SAndroid Build Coastguard Worker context->txDatagramQueue.pending, context->rxStatus.receivedAckSeq,
1058*84e33947SAndroid Build Coastguard Worker context->txStatus.sentSeq,
1059*84e33947SAndroid Build Coastguard Worker chppGetRxStatusLabel(context->rxStatus.state));
1060*84e33947SAndroid Build Coastguard Worker }
1061*84e33947SAndroid Build Coastguard Worker
1062*84e33947SAndroid Build Coastguard Worker chppMutexUnlock(&context->mutex);
1063*84e33947SAndroid Build Coastguard Worker
1064*84e33947SAndroid Build Coastguard Worker if (havePacketForLinkLayer) {
1065*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("TX->Link: len=%" PRIuSIZE " flags=0x%" PRIx8 " code=0x%" PRIx8
1066*84e33947SAndroid Build Coastguard Worker " ackSeq=%" PRIu8 " seq=%" PRIu8 " payloadLen=%" PRIu16
1067*84e33947SAndroid Build Coastguard Worker " pending=%" PRIu8,
1068*84e33947SAndroid Build Coastguard Worker context->linkBufferSize, txHeader->flags, txHeader->packetCode,
1069*84e33947SAndroid Build Coastguard Worker txHeader->ackSeq, txHeader->seq, txHeader->length,
1070*84e33947SAndroid Build Coastguard Worker context->txDatagramQueue.pending);
1071*84e33947SAndroid Build Coastguard Worker enum ChppLinkErrorCode error = chppSendPendingPacket(context);
1072*84e33947SAndroid Build Coastguard Worker
1073*84e33947SAndroid Build Coastguard Worker if (error != CHPP_LINK_ERROR_NONE_QUEUED) {
1074*84e33947SAndroid Build Coastguard Worker // Platform implementation for platformLinkSend() is synchronous or an
1075*84e33947SAndroid Build Coastguard Worker // error occurred. In either case, we should call chppLinkSendDoneCb()
1076*84e33947SAndroid Build Coastguard Worker // here to release the contents of tx link buffer.
1077*84e33947SAndroid Build Coastguard Worker chppLinkSendDoneCb(context, error);
1078*84e33947SAndroid Build Coastguard Worker }
1079*84e33947SAndroid Build Coastguard Worker }
1080*84e33947SAndroid Build Coastguard Worker
1081*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_CLIENT_ENABLED
1082*84e33947SAndroid Build Coastguard Worker { // create a scope to declare timeoutResponse (C89).
1083*84e33947SAndroid Build Coastguard Worker struct ChppAppHeader *timeoutResponse =
1084*84e33947SAndroid Build Coastguard Worker chppTransportGetRequestTimeoutResponse(context, CHPP_ENDPOINT_CLIENT);
1085*84e33947SAndroid Build Coastguard Worker
1086*84e33947SAndroid Build Coastguard Worker if (timeoutResponse != NULL) {
1087*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Response timeout H#%" PRIu8 " cmd=%" PRIu16 " ID=%" PRIu8,
1088*84e33947SAndroid Build Coastguard Worker timeoutResponse->handle, timeoutResponse->command,
1089*84e33947SAndroid Build Coastguard Worker timeoutResponse->transaction);
1090*84e33947SAndroid Build Coastguard Worker chppAppProcessRxDatagram(context->appContext, (uint8_t *)timeoutResponse,
1091*84e33947SAndroid Build Coastguard Worker sizeof(struct ChppAppHeader));
1092*84e33947SAndroid Build Coastguard Worker }
1093*84e33947SAndroid Build Coastguard Worker }
1094*84e33947SAndroid Build Coastguard Worker #endif // CHPP_CLIENT_ENABLED
1095*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_SERVICE_ENABLED
1096*84e33947SAndroid Build Coastguard Worker { // create a scope to declare timeoutResponse (C89).
1097*84e33947SAndroid Build Coastguard Worker struct ChppAppHeader *timeoutResponse =
1098*84e33947SAndroid Build Coastguard Worker chppTransportGetRequestTimeoutResponse(context, CHPP_ENDPOINT_SERVICE);
1099*84e33947SAndroid Build Coastguard Worker
1100*84e33947SAndroid Build Coastguard Worker if (timeoutResponse != NULL) {
1101*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Response timeout H#%" PRIu8 " cmd=%" PRIu16 " ID=%" PRIu8,
1102*84e33947SAndroid Build Coastguard Worker timeoutResponse->handle, timeoutResponse->command,
1103*84e33947SAndroid Build Coastguard Worker timeoutResponse->transaction);
1104*84e33947SAndroid Build Coastguard Worker chppAppProcessRxDatagram(context->appContext, (uint8_t *)timeoutResponse,
1105*84e33947SAndroid Build Coastguard Worker sizeof(struct ChppAppHeader));
1106*84e33947SAndroid Build Coastguard Worker }
1107*84e33947SAndroid Build Coastguard Worker }
1108*84e33947SAndroid Build Coastguard Worker #endif // CHPP_SERVICE_ENABLED
1109*84e33947SAndroid Build Coastguard Worker }
1110*84e33947SAndroid Build Coastguard Worker
1111*84e33947SAndroid Build Coastguard Worker /**
1112*84e33947SAndroid Build Coastguard Worker * Appends data from a buffer of length len to a link tx buffer, updating its
1113*84e33947SAndroid Build Coastguard Worker * length.
1114*84e33947SAndroid Build Coastguard Worker *
1115*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
1116*84e33947SAndroid Build Coastguard Worker * @param buf Input data to be copied from.
1117*84e33947SAndroid Build Coastguard Worker * @param len Length of input data in bytes.
1118*84e33947SAndroid Build Coastguard Worker */
chppAppendToPendingTxPacket(struct ChppTransportState * context,const uint8_t * buf,size_t len)1119*84e33947SAndroid Build Coastguard Worker static void chppAppendToPendingTxPacket(struct ChppTransportState *context,
1120*84e33947SAndroid Build Coastguard Worker const uint8_t *buf, size_t len) {
1121*84e33947SAndroid Build Coastguard Worker uint8_t *linkTxBuffer = context->linkApi->getTxBuffer(context->linkContext);
1122*84e33947SAndroid Build Coastguard Worker
1123*84e33947SAndroid Build Coastguard Worker size_t bufferSize = context->linkBufferSize;
1124*84e33947SAndroid Build Coastguard Worker
1125*84e33947SAndroid Build Coastguard Worker CHPP_ASSERT(bufferSize + len <=
1126*84e33947SAndroid Build Coastguard Worker context->linkApi->getConfig(context->linkContext).txBufferLen);
1127*84e33947SAndroid Build Coastguard Worker memcpy(&linkTxBuffer[bufferSize], buf, len);
1128*84e33947SAndroid Build Coastguard Worker context->linkBufferSize += len;
1129*84e33947SAndroid Build Coastguard Worker }
1130*84e33947SAndroid Build Coastguard Worker
1131*84e33947SAndroid Build Coastguard Worker /**
1132*84e33947SAndroid Build Coastguard Worker * @return A human readable form of the packet attribution.
1133*84e33947SAndroid Build Coastguard Worker */
chppGetPacketAttrStr(uint8_t packetCode)1134*84e33947SAndroid Build Coastguard Worker static const char *chppGetPacketAttrStr(uint8_t packetCode) {
1135*84e33947SAndroid Build Coastguard Worker switch (CHPP_TRANSPORT_GET_ATTR(packetCode)) {
1136*84e33947SAndroid Build Coastguard Worker case CHPP_TRANSPORT_ATTR_RESET:
1137*84e33947SAndroid Build Coastguard Worker return "(RESET)";
1138*84e33947SAndroid Build Coastguard Worker case CHPP_TRANSPORT_ATTR_RESET_ACK:
1139*84e33947SAndroid Build Coastguard Worker return "(RESET-ACK)";
1140*84e33947SAndroid Build Coastguard Worker case CHPP_TRANSPORT_ATTR_LOOPBACK_REQUEST:
1141*84e33947SAndroid Build Coastguard Worker return "(LOOP-REQ)";
1142*84e33947SAndroid Build Coastguard Worker case CHPP_TRANSPORT_ATTR_LOOPBACK_RESPONSE:
1143*84e33947SAndroid Build Coastguard Worker return "(LOOP-RES)";
1144*84e33947SAndroid Build Coastguard Worker default:
1145*84e33947SAndroid Build Coastguard Worker return "";
1146*84e33947SAndroid Build Coastguard Worker }
1147*84e33947SAndroid Build Coastguard Worker }
1148*84e33947SAndroid Build Coastguard Worker
1149*84e33947SAndroid Build Coastguard Worker /**
1150*84e33947SAndroid Build Coastguard Worker * Enqueues an outgoing datagram of a specified length. The payload must have
1151*84e33947SAndroid Build Coastguard Worker * been allocated by the caller using chppMalloc.
1152*84e33947SAndroid Build Coastguard Worker *
1153*84e33947SAndroid Build Coastguard Worker * If enqueueing is successful, the payload will be freed by this function
1154*84e33947SAndroid Build Coastguard Worker * once it has been sent out.
1155*84e33947SAndroid Build Coastguard Worker * If enqueueing is unsuccessful, it is up to the caller to decide when or if
1156*84e33947SAndroid Build Coastguard Worker * to free the payload and/or resend it later.
1157*84e33947SAndroid Build Coastguard Worker *
1158*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
1159*84e33947SAndroid Build Coastguard Worker * @param packetCode Error code and packet attributes to be sent.
1160*84e33947SAndroid Build Coastguard Worker * @param buf Datagram payload allocated through chppMalloc. Cannot be null.
1161*84e33947SAndroid Build Coastguard Worker * @param len Datagram length in bytes.
1162*84e33947SAndroid Build Coastguard Worker *
1163*84e33947SAndroid Build Coastguard Worker * @return True informs the sender that the datagram was successfully enqueued.
1164*84e33947SAndroid Build Coastguard Worker * False informs the sender that the queue was full.
1165*84e33947SAndroid Build Coastguard Worker */
chppEnqueueTxDatagram(struct ChppTransportState * context,uint8_t packetCode,void * buf,size_t len)1166*84e33947SAndroid Build Coastguard Worker static bool chppEnqueueTxDatagram(struct ChppTransportState *context,
1167*84e33947SAndroid Build Coastguard Worker uint8_t packetCode, void *buf, size_t len) {
1168*84e33947SAndroid Build Coastguard Worker bool success = false;
1169*84e33947SAndroid Build Coastguard Worker
1170*84e33947SAndroid Build Coastguard Worker if (len == 0) {
1171*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_ASSERT_LOG(false, "Enqueue TX len=0!");
1172*84e33947SAndroid Build Coastguard Worker
1173*84e33947SAndroid Build Coastguard Worker } else {
1174*84e33947SAndroid Build Coastguard Worker if ((len < sizeof(struct ChppAppHeader)) ||
1175*84e33947SAndroid Build Coastguard Worker (CHPP_TRANSPORT_GET_ATTR(packetCode) != 0)) {
1176*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("Enqueue TX: code=0x%" PRIx8 "%s len=%" PRIuSIZE
1177*84e33947SAndroid Build Coastguard Worker " pending=%" PRIu8,
1178*84e33947SAndroid Build Coastguard Worker packetCode, chppGetPacketAttrStr(packetCode), len,
1179*84e33947SAndroid Build Coastguard Worker (uint8_t)(context->txDatagramQueue.pending + 1));
1180*84e33947SAndroid Build Coastguard Worker } else {
1181*84e33947SAndroid Build Coastguard Worker struct ChppAppHeader *header = buf;
1182*84e33947SAndroid Build Coastguard Worker CHPP_LOGD(
1183*84e33947SAndroid Build Coastguard Worker "Enqueue TX: len=%" PRIuSIZE " H#%" PRIu8 " type=0x%" PRIx8
1184*84e33947SAndroid Build Coastguard Worker " ID=%" PRIu8 " err=%" PRIu8 " cmd=0x%" PRIx16 " pending=%" PRIu8,
1185*84e33947SAndroid Build Coastguard Worker len, header->handle, header->type, header->transaction, header->error,
1186*84e33947SAndroid Build Coastguard Worker header->command, (uint8_t)(context->txDatagramQueue.pending + 1));
1187*84e33947SAndroid Build Coastguard Worker }
1188*84e33947SAndroid Build Coastguard Worker
1189*84e33947SAndroid Build Coastguard Worker chppMutexLock(&context->mutex);
1190*84e33947SAndroid Build Coastguard Worker
1191*84e33947SAndroid Build Coastguard Worker if (context->txDatagramQueue.pending >= CHPP_TX_DATAGRAM_QUEUE_LEN) {
1192*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Cannot enqueue TX datagram");
1193*84e33947SAndroid Build Coastguard Worker
1194*84e33947SAndroid Build Coastguard Worker } else {
1195*84e33947SAndroid Build Coastguard Worker uint16_t end =
1196*84e33947SAndroid Build Coastguard Worker (context->txDatagramQueue.front + context->txDatagramQueue.pending) %
1197*84e33947SAndroid Build Coastguard Worker CHPP_TX_DATAGRAM_QUEUE_LEN;
1198*84e33947SAndroid Build Coastguard Worker context->txDatagramQueue.datagram[end].length = len;
1199*84e33947SAndroid Build Coastguard Worker context->txDatagramQueue.datagram[end].payload = buf;
1200*84e33947SAndroid Build Coastguard Worker context->txDatagramQueue.pending++;
1201*84e33947SAndroid Build Coastguard Worker
1202*84e33947SAndroid Build Coastguard Worker if (context->txDatagramQueue.pending == 1) {
1203*84e33947SAndroid Build Coastguard Worker // Queue was empty prior. Need to kickstart transmission.
1204*84e33947SAndroid Build Coastguard Worker chppEnqueueTxPacket(context, packetCode);
1205*84e33947SAndroid Build Coastguard Worker }
1206*84e33947SAndroid Build Coastguard Worker
1207*84e33947SAndroid Build Coastguard Worker success = true;
1208*84e33947SAndroid Build Coastguard Worker }
1209*84e33947SAndroid Build Coastguard Worker
1210*84e33947SAndroid Build Coastguard Worker chppMutexUnlock(&context->mutex);
1211*84e33947SAndroid Build Coastguard Worker }
1212*84e33947SAndroid Build Coastguard Worker
1213*84e33947SAndroid Build Coastguard Worker return success;
1214*84e33947SAndroid Build Coastguard Worker }
1215*84e33947SAndroid Build Coastguard Worker
1216*84e33947SAndroid Build Coastguard Worker /**
1217*84e33947SAndroid Build Coastguard Worker * Sends the pending outgoing packet over to the link
1218*84e33947SAndroid Build Coastguard Worker * layer using Send() and updates the last Tx packet time.
1219*84e33947SAndroid Build Coastguard Worker *
1220*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
1221*84e33947SAndroid Build Coastguard Worker *
1222*84e33947SAndroid Build Coastguard Worker * @return Result of Send().
1223*84e33947SAndroid Build Coastguard Worker */
chppSendPendingPacket(struct ChppTransportState * context)1224*84e33947SAndroid Build Coastguard Worker static enum ChppLinkErrorCode chppSendPendingPacket(
1225*84e33947SAndroid Build Coastguard Worker struct ChppTransportState *context) {
1226*84e33947SAndroid Build Coastguard Worker enum ChppLinkErrorCode error =
1227*84e33947SAndroid Build Coastguard Worker context->linkApi->send(context->linkContext, context->linkBufferSize);
1228*84e33947SAndroid Build Coastguard Worker
1229*84e33947SAndroid Build Coastguard Worker context->txStatus.lastTxTimeNs = chppGetCurrentTimeNs();
1230*84e33947SAndroid Build Coastguard Worker
1231*84e33947SAndroid Build Coastguard Worker return error;
1232*84e33947SAndroid Build Coastguard Worker }
1233*84e33947SAndroid Build Coastguard Worker
1234*84e33947SAndroid Build Coastguard Worker /**
1235*84e33947SAndroid Build Coastguard Worker * Resets the transport state, maintaining the link layer parameters.
1236*84e33947SAndroid Build Coastguard Worker *
1237*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
1238*84e33947SAndroid Build Coastguard Worker */
chppResetTransportContext(struct ChppTransportState * context)1239*84e33947SAndroid Build Coastguard Worker static void chppResetTransportContext(struct ChppTransportState *context) {
1240*84e33947SAndroid Build Coastguard Worker memset(&context->rxStatus, 0, sizeof(struct ChppRxStatus));
1241*84e33947SAndroid Build Coastguard Worker memset(&context->rxDatagram, 0, sizeof(struct ChppDatagram));
1242*84e33947SAndroid Build Coastguard Worker
1243*84e33947SAndroid Build Coastguard Worker memset(&context->txStatus, 0, sizeof(struct ChppTxStatus));
1244*84e33947SAndroid Build Coastguard Worker memset(&context->txDatagramQueue, 0, sizeof(struct ChppTxDatagramQueue));
1245*84e33947SAndroid Build Coastguard Worker
1246*84e33947SAndroid Build Coastguard Worker context->txStatus.sentSeq =
1247*84e33947SAndroid Build Coastguard Worker UINT8_MAX; // So that the seq # of the first TX packet is 0
1248*84e33947SAndroid Build Coastguard Worker context->resetState = CHPP_RESET_STATE_RESETTING;
1249*84e33947SAndroid Build Coastguard Worker }
1250*84e33947SAndroid Build Coastguard Worker
1251*84e33947SAndroid Build Coastguard Worker /**
1252*84e33947SAndroid Build Coastguard Worker * Re-initializes the CHPP transport and app layer states, e.g. when receiving a
1253*84e33947SAndroid Build Coastguard Worker * reset packet, and sends out a reset or reset-ack packet over the link in
1254*84e33947SAndroid Build Coastguard Worker * order to reset the remote side or inform the counterpart of a reset,
1255*84e33947SAndroid Build Coastguard Worker * respectively.
1256*84e33947SAndroid Build Coastguard Worker *
1257*84e33947SAndroid Build Coastguard Worker * If the link layer is busy, this function will reset the link as well.
1258*84e33947SAndroid Build Coastguard Worker * This function retains and restores the platform-specific values of
1259*84e33947SAndroid Build Coastguard Worker * transportContext.linkContext.
1260*84e33947SAndroid Build Coastguard Worker *
1261*84e33947SAndroid Build Coastguard Worker * @param transportContext State of the transport layer.
1262*84e33947SAndroid Build Coastguard Worker * @param resetType Type of reset to send after resetting CHPP (reset vs.
1263*84e33947SAndroid Build Coastguard Worker * reset-ack), as defined in the ChppTransportPacketAttributes struct.
1264*84e33947SAndroid Build Coastguard Worker * @param error Provides the error that led to the reset.
1265*84e33947SAndroid Build Coastguard Worker */
chppReset(struct ChppTransportState * transportContext,enum ChppTransportPacketAttributes resetType,enum ChppTransportErrorCode error)1266*84e33947SAndroid Build Coastguard Worker static void chppReset(struct ChppTransportState *transportContext,
1267*84e33947SAndroid Build Coastguard Worker enum ChppTransportPacketAttributes resetType,
1268*84e33947SAndroid Build Coastguard Worker enum ChppTransportErrorCode error) {
1269*84e33947SAndroid Build Coastguard Worker // TODO: Configure transport layer based on (optional?) received config before
1270*84e33947SAndroid Build Coastguard Worker // datagram is wiped
1271*84e33947SAndroid Build Coastguard Worker
1272*84e33947SAndroid Build Coastguard Worker chppMutexLock(&transportContext->mutex);
1273*84e33947SAndroid Build Coastguard Worker struct ChppAppState *appContext = transportContext->appContext;
1274*84e33947SAndroid Build Coastguard Worker transportContext->resetState = CHPP_RESET_STATE_RESETTING;
1275*84e33947SAndroid Build Coastguard Worker
1276*84e33947SAndroid Build Coastguard Worker // Reset asynchronous link layer if busy
1277*84e33947SAndroid Build Coastguard Worker if (transportContext->txStatus.linkBusy == true) {
1278*84e33947SAndroid Build Coastguard Worker // TODO: Give time for link layer to finish before resorting to a reset
1279*84e33947SAndroid Build Coastguard Worker
1280*84e33947SAndroid Build Coastguard Worker transportContext->linkApi->reset(transportContext->linkContext);
1281*84e33947SAndroid Build Coastguard Worker }
1282*84e33947SAndroid Build Coastguard Worker
1283*84e33947SAndroid Build Coastguard Worker // Free memory allocated for any ongoing rx datagrams
1284*84e33947SAndroid Build Coastguard Worker if (transportContext->rxDatagram.length > 0) {
1285*84e33947SAndroid Build Coastguard Worker transportContext->rxDatagram.length = 0;
1286*84e33947SAndroid Build Coastguard Worker CHPP_FREE_AND_NULLIFY(transportContext->rxDatagram.payload);
1287*84e33947SAndroid Build Coastguard Worker }
1288*84e33947SAndroid Build Coastguard Worker
1289*84e33947SAndroid Build Coastguard Worker // Free memory allocated for any ongoing tx datagrams
1290*84e33947SAndroid Build Coastguard Worker for (size_t i = 0; i < CHPP_TX_DATAGRAM_QUEUE_LEN; i++) {
1291*84e33947SAndroid Build Coastguard Worker if (transportContext->txDatagramQueue.datagram[i].length > 0) {
1292*84e33947SAndroid Build Coastguard Worker CHPP_FREE_AND_NULLIFY(
1293*84e33947SAndroid Build Coastguard Worker transportContext->txDatagramQueue.datagram[i].payload);
1294*84e33947SAndroid Build Coastguard Worker }
1295*84e33947SAndroid Build Coastguard Worker }
1296*84e33947SAndroid Build Coastguard Worker
1297*84e33947SAndroid Build Coastguard Worker // Reset Transport Layer but restore Rx sequence number and packet code
1298*84e33947SAndroid Build Coastguard Worker // (context->rxHeader is not wiped in reset)
1299*84e33947SAndroid Build Coastguard Worker chppResetTransportContext(transportContext);
1300*84e33947SAndroid Build Coastguard Worker transportContext->rxStatus.receivedPacketCode =
1301*84e33947SAndroid Build Coastguard Worker transportContext->rxHeader.packetCode;
1302*84e33947SAndroid Build Coastguard Worker transportContext->rxStatus.expectedSeq = transportContext->rxHeader.seq + 1;
1303*84e33947SAndroid Build Coastguard Worker
1304*84e33947SAndroid Build Coastguard Worker // Send reset or reset-ACK
1305*84e33947SAndroid Build Coastguard Worker chppMutexUnlock(&transportContext->mutex);
1306*84e33947SAndroid Build Coastguard Worker chppTransportSendReset(transportContext, resetType, error);
1307*84e33947SAndroid Build Coastguard Worker
1308*84e33947SAndroid Build Coastguard Worker // Inform the App Layer that a reset has completed
1309*84e33947SAndroid Build Coastguard Worker if (resetType == CHPP_TRANSPORT_ATTR_RESET_ACK) {
1310*84e33947SAndroid Build Coastguard Worker chppAppProcessReset(appContext);
1311*84e33947SAndroid Build Coastguard Worker } // else reset is sent out. Rx of reset-ack will indicate completion.
1312*84e33947SAndroid Build Coastguard Worker }
1313*84e33947SAndroid Build Coastguard Worker
1314*84e33947SAndroid Build Coastguard Worker /**
1315*84e33947SAndroid Build Coastguard Worker * Checks for a timed out request and generates a timeout response if a timeout
1316*84e33947SAndroid Build Coastguard Worker * has occurred.
1317*84e33947SAndroid Build Coastguard Worker *
1318*84e33947SAndroid Build Coastguard Worker * @param context State of the transport layer.
1319*84e33947SAndroid Build Coastguard Worker * @param type The type of the endpoint.
1320*84e33947SAndroid Build Coastguard Worker * @return App layer response header if a timeout has occurred. Null otherwise.
1321*84e33947SAndroid Build Coastguard Worker */
chppTransportGetRequestTimeoutResponse(struct ChppTransportState * context,enum ChppEndpointType type)1322*84e33947SAndroid Build Coastguard Worker struct ChppAppHeader *chppTransportGetRequestTimeoutResponse(
1323*84e33947SAndroid Build Coastguard Worker struct ChppTransportState *context, enum ChppEndpointType type) {
1324*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(context);
1325*84e33947SAndroid Build Coastguard Worker
1326*84e33947SAndroid Build Coastguard Worker struct ChppAppState *appState = context->appContext;
1327*84e33947SAndroid Build Coastguard Worker struct ChppAppHeader *response = NULL;
1328*84e33947SAndroid Build Coastguard Worker
1329*84e33947SAndroid Build Coastguard Worker bool timeoutEndpointFound = false;
1330*84e33947SAndroid Build Coastguard Worker uint8_t timedOutEndpointIdx;
1331*84e33947SAndroid Build Coastguard Worker uint16_t timedOutCmd;
1332*84e33947SAndroid Build Coastguard Worker
1333*84e33947SAndroid Build Coastguard Worker chppMutexLock(&context->mutex);
1334*84e33947SAndroid Build Coastguard Worker
1335*84e33947SAndroid Build Coastguard Worker if (*getNextRequestTimeoutNs(appState, type) <= chppGetCurrentTimeNs()) {
1336*84e33947SAndroid Build Coastguard Worker // Determine which request has timed out
1337*84e33947SAndroid Build Coastguard Worker const uint8_t endpointCount = getRegisteredEndpointCount(appState, type);
1338*84e33947SAndroid Build Coastguard Worker uint64_t firstTimeout = CHPP_TIME_MAX;
1339*84e33947SAndroid Build Coastguard Worker
1340*84e33947SAndroid Build Coastguard Worker for (uint8_t endpointIdx = 0; endpointIdx < endpointCount; endpointIdx++) {
1341*84e33947SAndroid Build Coastguard Worker const uint16_t cmdCount =
1342*84e33947SAndroid Build Coastguard Worker getRegisteredEndpointOutReqCount(appState, endpointIdx, type);
1343*84e33947SAndroid Build Coastguard Worker const struct ChppEndpointState *endpointState =
1344*84e33947SAndroid Build Coastguard Worker getRegisteredEndpointState(appState, endpointIdx, type);
1345*84e33947SAndroid Build Coastguard Worker const struct ChppOutgoingRequestState *reqStates =
1346*84e33947SAndroid Build Coastguard Worker &endpointState->outReqStates[0];
1347*84e33947SAndroid Build Coastguard Worker for (uint16_t cmdIdx = 0; cmdIdx < cmdCount; cmdIdx++) {
1348*84e33947SAndroid Build Coastguard Worker const struct ChppOutgoingRequestState *reqState = &reqStates[cmdIdx];
1349*84e33947SAndroid Build Coastguard Worker
1350*84e33947SAndroid Build Coastguard Worker if (reqState->requestState == CHPP_REQUEST_STATE_REQUEST_SENT &&
1351*84e33947SAndroid Build Coastguard Worker reqState->responseTimeNs != CHPP_TIME_NONE &&
1352*84e33947SAndroid Build Coastguard Worker reqState->responseTimeNs < firstTimeout) {
1353*84e33947SAndroid Build Coastguard Worker firstTimeout = reqState->responseTimeNs;
1354*84e33947SAndroid Build Coastguard Worker timedOutEndpointIdx = endpointIdx;
1355*84e33947SAndroid Build Coastguard Worker timedOutCmd = cmdIdx;
1356*84e33947SAndroid Build Coastguard Worker timeoutEndpointFound = true;
1357*84e33947SAndroid Build Coastguard Worker }
1358*84e33947SAndroid Build Coastguard Worker }
1359*84e33947SAndroid Build Coastguard Worker }
1360*84e33947SAndroid Build Coastguard Worker
1361*84e33947SAndroid Build Coastguard Worker if (!timeoutEndpointFound) {
1362*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Timeout at %" PRIu64 " but no endpoint",
1363*84e33947SAndroid Build Coastguard Worker *getNextRequestTimeoutNs(appState, type) / CHPP_NSEC_PER_MSEC);
1364*84e33947SAndroid Build Coastguard Worker chppRecalculateNextTimeout(appState, CHPP_ENDPOINT_CLIENT);
1365*84e33947SAndroid Build Coastguard Worker }
1366*84e33947SAndroid Build Coastguard Worker }
1367*84e33947SAndroid Build Coastguard Worker
1368*84e33947SAndroid Build Coastguard Worker if (timeoutEndpointFound) {
1369*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Endpoint=%" PRIu8 " cmd=%" PRIu16 " timed out",
1370*84e33947SAndroid Build Coastguard Worker timedOutEndpointIdx, timedOutCmd);
1371*84e33947SAndroid Build Coastguard Worker response = chppMalloc(sizeof(struct ChppAppHeader));
1372*84e33947SAndroid Build Coastguard Worker if (response == NULL) {
1373*84e33947SAndroid Build Coastguard Worker CHPP_LOG_OOM();
1374*84e33947SAndroid Build Coastguard Worker } else {
1375*84e33947SAndroid Build Coastguard Worker const struct ChppEndpointState *endpointState =
1376*84e33947SAndroid Build Coastguard Worker getRegisteredEndpointState(appState, timedOutEndpointIdx, type);
1377*84e33947SAndroid Build Coastguard Worker response->handle = endpointState->handle;
1378*84e33947SAndroid Build Coastguard Worker response->type = type == CHPP_ENDPOINT_CLIENT
1379*84e33947SAndroid Build Coastguard Worker ? CHPP_MESSAGE_TYPE_SERVICE_RESPONSE
1380*84e33947SAndroid Build Coastguard Worker : CHPP_MESSAGE_TYPE_CLIENT_RESPONSE;
1381*84e33947SAndroid Build Coastguard Worker response->transaction =
1382*84e33947SAndroid Build Coastguard Worker endpointState->outReqStates[timedOutCmd].transaction;
1383*84e33947SAndroid Build Coastguard Worker response->error = CHPP_APP_ERROR_TIMEOUT;
1384*84e33947SAndroid Build Coastguard Worker response->command = timedOutCmd;
1385*84e33947SAndroid Build Coastguard Worker }
1386*84e33947SAndroid Build Coastguard Worker }
1387*84e33947SAndroid Build Coastguard Worker
1388*84e33947SAndroid Build Coastguard Worker chppMutexUnlock(&context->mutex);
1389*84e33947SAndroid Build Coastguard Worker
1390*84e33947SAndroid Build Coastguard Worker return response;
1391*84e33947SAndroid Build Coastguard Worker }
1392*84e33947SAndroid Build Coastguard Worker
1393*84e33947SAndroid Build Coastguard Worker /************************************************
1394*84e33947SAndroid Build Coastguard Worker * Public Functions
1395*84e33947SAndroid Build Coastguard Worker ***********************************************/
1396*84e33947SAndroid Build Coastguard Worker
chppTransportInit(struct ChppTransportState * transportContext,struct ChppAppState * appContext,void * linkContext,const struct ChppLinkApi * linkApi)1397*84e33947SAndroid Build Coastguard Worker void chppTransportInit(struct ChppTransportState *transportContext,
1398*84e33947SAndroid Build Coastguard Worker struct ChppAppState *appContext, void *linkContext,
1399*84e33947SAndroid Build Coastguard Worker const struct ChppLinkApi *linkApi) {
1400*84e33947SAndroid Build Coastguard Worker CHPP_NOT_NULL(transportContext);
1401*84e33947SAndroid Build Coastguard Worker CHPP_NOT_NULL(appContext);
1402*84e33947SAndroid Build Coastguard Worker
1403*84e33947SAndroid Build Coastguard Worker CHPP_ASSERT_LOG(!transportContext->initialized,
1404*84e33947SAndroid Build Coastguard Worker "CHPP transport already init");
1405*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("Initializing CHPP transport");
1406*84e33947SAndroid Build Coastguard Worker
1407*84e33947SAndroid Build Coastguard Worker chppResetTransportContext(transportContext);
1408*84e33947SAndroid Build Coastguard Worker chppMutexInit(&transportContext->mutex);
1409*84e33947SAndroid Build Coastguard Worker chppNotifierInit(&transportContext->notifier);
1410*84e33947SAndroid Build Coastguard Worker chppConditionVariableInit(&transportContext->resetCondVar);
1411*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_ENABLE_WORK_MONITOR
1412*84e33947SAndroid Build Coastguard Worker chppWorkMonitorInit(&transportContext->workMonitor);
1413*84e33947SAndroid Build Coastguard Worker #endif
1414*84e33947SAndroid Build Coastguard Worker
1415*84e33947SAndroid Build Coastguard Worker transportContext->appContext = appContext;
1416*84e33947SAndroid Build Coastguard Worker transportContext->initialized = true;
1417*84e33947SAndroid Build Coastguard Worker
1418*84e33947SAndroid Build Coastguard Worker CHPP_NOT_NULL(linkApi);
1419*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(linkApi->init);
1420*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(linkApi->deinit);
1421*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(linkApi->send);
1422*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(linkApi->doWork);
1423*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(linkApi->reset);
1424*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(linkApi->getConfig);
1425*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(linkApi->getTxBuffer);
1426*84e33947SAndroid Build Coastguard Worker transportContext->linkApi = linkApi;
1427*84e33947SAndroid Build Coastguard Worker
1428*84e33947SAndroid Build Coastguard Worker CHPP_NOT_NULL(linkContext);
1429*84e33947SAndroid Build Coastguard Worker linkApi->init(linkContext, transportContext);
1430*84e33947SAndroid Build Coastguard Worker transportContext->linkContext = linkContext;
1431*84e33947SAndroid Build Coastguard Worker
1432*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_DEBUG_ASSERT_ENABLED
1433*84e33947SAndroid Build Coastguard Worker const struct ChppLinkConfiguration linkConfig =
1434*84e33947SAndroid Build Coastguard Worker linkApi->getConfig(linkContext);
1435*84e33947SAndroid Build Coastguard Worker CHPP_ASSERT_LOG(
1436*84e33947SAndroid Build Coastguard Worker linkConfig.txBufferLen > CHPP_TRANSPORT_ENCODING_OVERHEAD_BYTES,
1437*84e33947SAndroid Build Coastguard Worker "The link TX buffer is too small");
1438*84e33947SAndroid Build Coastguard Worker CHPP_ASSERT_LOG(
1439*84e33947SAndroid Build Coastguard Worker linkConfig.rxBufferLen > CHPP_TRANSPORT_ENCODING_OVERHEAD_BYTES,
1440*84e33947SAndroid Build Coastguard Worker "The link RX buffer is too small");
1441*84e33947SAndroid Build Coastguard Worker #endif // CHPP_DEBUG_ASSERT_ENABLED
1442*84e33947SAndroid Build Coastguard Worker }
1443*84e33947SAndroid Build Coastguard Worker
chppTransportDeinit(struct ChppTransportState * transportContext)1444*84e33947SAndroid Build Coastguard Worker void chppTransportDeinit(struct ChppTransportState *transportContext) {
1445*84e33947SAndroid Build Coastguard Worker CHPP_NOT_NULL(transportContext);
1446*84e33947SAndroid Build Coastguard Worker CHPP_ASSERT_LOG(transportContext->initialized,
1447*84e33947SAndroid Build Coastguard Worker "CHPP transport already deinitialized");
1448*84e33947SAndroid Build Coastguard Worker
1449*84e33947SAndroid Build Coastguard Worker transportContext->linkApi->deinit(transportContext->linkContext);
1450*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_ENABLE_WORK_MONITOR
1451*84e33947SAndroid Build Coastguard Worker chppWorkMonitorDeinit(&transportContext->workMonitor);
1452*84e33947SAndroid Build Coastguard Worker #endif
1453*84e33947SAndroid Build Coastguard Worker chppConditionVariableDeinit(&transportContext->resetCondVar);
1454*84e33947SAndroid Build Coastguard Worker chppNotifierDeinit(&transportContext->notifier);
1455*84e33947SAndroid Build Coastguard Worker chppMutexDeinit(&transportContext->mutex);
1456*84e33947SAndroid Build Coastguard Worker
1457*84e33947SAndroid Build Coastguard Worker chppClearTxDatagramQueue(transportContext);
1458*84e33947SAndroid Build Coastguard Worker
1459*84e33947SAndroid Build Coastguard Worker CHPP_FREE_AND_NULLIFY(transportContext->rxDatagram.payload);
1460*84e33947SAndroid Build Coastguard Worker
1461*84e33947SAndroid Build Coastguard Worker transportContext->initialized = false;
1462*84e33947SAndroid Build Coastguard Worker }
1463*84e33947SAndroid Build Coastguard Worker
chppTransportWaitForResetComplete(struct ChppTransportState * transportContext,uint64_t timeoutMs)1464*84e33947SAndroid Build Coastguard Worker bool chppTransportWaitForResetComplete(
1465*84e33947SAndroid Build Coastguard Worker struct ChppTransportState *transportContext, uint64_t timeoutMs) {
1466*84e33947SAndroid Build Coastguard Worker bool success = true;
1467*84e33947SAndroid Build Coastguard Worker chppMutexLock(&transportContext->mutex);
1468*84e33947SAndroid Build Coastguard Worker while (success && transportContext->resetState != CHPP_RESET_STATE_NONE) {
1469*84e33947SAndroid Build Coastguard Worker success = chppConditionVariableTimedWait(&transportContext->resetCondVar,
1470*84e33947SAndroid Build Coastguard Worker &transportContext->mutex,
1471*84e33947SAndroid Build Coastguard Worker timeoutMs * CHPP_NSEC_PER_MSEC);
1472*84e33947SAndroid Build Coastguard Worker }
1473*84e33947SAndroid Build Coastguard Worker chppMutexUnlock(&transportContext->mutex);
1474*84e33947SAndroid Build Coastguard Worker return success;
1475*84e33947SAndroid Build Coastguard Worker }
1476*84e33947SAndroid Build Coastguard Worker
chppRxDataCb(struct ChppTransportState * context,const uint8_t * buf,size_t len)1477*84e33947SAndroid Build Coastguard Worker bool chppRxDataCb(struct ChppTransportState *context, const uint8_t *buf,
1478*84e33947SAndroid Build Coastguard Worker size_t len) {
1479*84e33947SAndroid Build Coastguard Worker CHPP_NOT_NULL(buf);
1480*84e33947SAndroid Build Coastguard Worker CHPP_NOT_NULL(context);
1481*84e33947SAndroid Build Coastguard Worker
1482*84e33947SAndroid Build Coastguard Worker chppMutexLock(&context->mutex);
1483*84e33947SAndroid Build Coastguard Worker if (context->rxStatus.state != CHPP_STATE_PREAMBLE &&
1484*84e33947SAndroid Build Coastguard Worker chppGetCurrentTimeNs() >
1485*84e33947SAndroid Build Coastguard Worker context->rxStatus.packetStartTimeNs + CHPP_TRANSPORT_RX_TIMEOUT_NS) {
1486*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Packet RX timeout");
1487*84e33947SAndroid Build Coastguard Worker chppAbortRxPacket(context);
1488*84e33947SAndroid Build Coastguard Worker }
1489*84e33947SAndroid Build Coastguard Worker chppMutexUnlock(&context->mutex);
1490*84e33947SAndroid Build Coastguard Worker
1491*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("RX %" PRIuSIZE " bytes: state=%s", len,
1492*84e33947SAndroid Build Coastguard Worker chppGetRxStatusLabel(context->rxStatus.state));
1493*84e33947SAndroid Build Coastguard Worker uint64_t now = chppGetCurrentTimeNs();
1494*84e33947SAndroid Build Coastguard Worker context->rxStatus.lastDataTimeMs = (uint32_t)(now / CHPP_NSEC_PER_MSEC);
1495*84e33947SAndroid Build Coastguard Worker context->rxStatus.numTotalDataBytes += len;
1496*84e33947SAndroid Build Coastguard Worker
1497*84e33947SAndroid Build Coastguard Worker size_t consumed = 0;
1498*84e33947SAndroid Build Coastguard Worker while (consumed < len) {
1499*84e33947SAndroid Build Coastguard Worker chppMutexLock(&context->mutex);
1500*84e33947SAndroid Build Coastguard Worker // TODO: Investigate fine-grained locking, e.g. separating variables that
1501*84e33947SAndroid Build Coastguard Worker // are only relevant to a particular path.
1502*84e33947SAndroid Build Coastguard Worker // Also consider removing some of the finer-grained locks altogether for
1503*84e33947SAndroid Build Coastguard Worker // non-multithreaded environments with clear documentation.
1504*84e33947SAndroid Build Coastguard Worker
1505*84e33947SAndroid Build Coastguard Worker switch (context->rxStatus.state) {
1506*84e33947SAndroid Build Coastguard Worker case CHPP_STATE_PREAMBLE:
1507*84e33947SAndroid Build Coastguard Worker consumed +=
1508*84e33947SAndroid Build Coastguard Worker chppConsumePreamble(context, &buf[consumed], len - consumed);
1509*84e33947SAndroid Build Coastguard Worker break;
1510*84e33947SAndroid Build Coastguard Worker
1511*84e33947SAndroid Build Coastguard Worker case CHPP_STATE_HEADER:
1512*84e33947SAndroid Build Coastguard Worker consumed += chppConsumeHeader(context, &buf[consumed], len - consumed);
1513*84e33947SAndroid Build Coastguard Worker break;
1514*84e33947SAndroid Build Coastguard Worker
1515*84e33947SAndroid Build Coastguard Worker case CHPP_STATE_PAYLOAD:
1516*84e33947SAndroid Build Coastguard Worker consumed += chppConsumePayload(context, &buf[consumed], len - consumed);
1517*84e33947SAndroid Build Coastguard Worker break;
1518*84e33947SAndroid Build Coastguard Worker
1519*84e33947SAndroid Build Coastguard Worker case CHPP_STATE_FOOTER:
1520*84e33947SAndroid Build Coastguard Worker consumed += chppConsumeFooter(context, &buf[consumed], len - consumed);
1521*84e33947SAndroid Build Coastguard Worker break;
1522*84e33947SAndroid Build Coastguard Worker
1523*84e33947SAndroid Build Coastguard Worker default:
1524*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_ASSERT_LOG(false, "Invalid RX state %" PRIu8,
1525*84e33947SAndroid Build Coastguard Worker context->rxStatus.state);
1526*84e33947SAndroid Build Coastguard Worker chppSetRxState(context, CHPP_STATE_PREAMBLE);
1527*84e33947SAndroid Build Coastguard Worker }
1528*84e33947SAndroid Build Coastguard Worker
1529*84e33947SAndroid Build Coastguard Worker chppMutexUnlock(&context->mutex);
1530*84e33947SAndroid Build Coastguard Worker }
1531*84e33947SAndroid Build Coastguard Worker
1532*84e33947SAndroid Build Coastguard Worker return (context->rxStatus.state == CHPP_STATE_PREAMBLE &&
1533*84e33947SAndroid Build Coastguard Worker context->rxStatus.locInState == 0);
1534*84e33947SAndroid Build Coastguard Worker }
1535*84e33947SAndroid Build Coastguard Worker
chppRxPacketCompleteCb(struct ChppTransportState * context)1536*84e33947SAndroid Build Coastguard Worker void chppRxPacketCompleteCb(struct ChppTransportState *context) {
1537*84e33947SAndroid Build Coastguard Worker chppMutexLock(&context->mutex);
1538*84e33947SAndroid Build Coastguard Worker if (context->rxStatus.state != CHPP_STATE_PREAMBLE) {
1539*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("RX pkt ended early: state=%s seq=%" PRIu8 " len=%" PRIu16,
1540*84e33947SAndroid Build Coastguard Worker chppGetRxStatusLabel(context->rxStatus.state),
1541*84e33947SAndroid Build Coastguard Worker context->rxHeader.seq, context->rxHeader.length);
1542*84e33947SAndroid Build Coastguard Worker chppAbortRxPacket(context);
1543*84e33947SAndroid Build Coastguard Worker chppEnqueueTxPacket(context, CHPP_TRANSPORT_ERROR_HEADER); // NACK
1544*84e33947SAndroid Build Coastguard Worker }
1545*84e33947SAndroid Build Coastguard Worker chppMutexUnlock(&context->mutex);
1546*84e33947SAndroid Build Coastguard Worker }
1547*84e33947SAndroid Build Coastguard Worker
chppEnqueueTxDatagramOrFail(struct ChppTransportState * context,void * buf,size_t len)1548*84e33947SAndroid Build Coastguard Worker bool chppEnqueueTxDatagramOrFail(struct ChppTransportState *context, void *buf,
1549*84e33947SAndroid Build Coastguard Worker size_t len) {
1550*84e33947SAndroid Build Coastguard Worker bool success = false;
1551*84e33947SAndroid Build Coastguard Worker bool resetting = (context->resetState == CHPP_RESET_STATE_RESETTING);
1552*84e33947SAndroid Build Coastguard Worker
1553*84e33947SAndroid Build Coastguard Worker if (len == 0) {
1554*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_ASSERT_LOG(false, "Enqueue datagram len=0!");
1555*84e33947SAndroid Build Coastguard Worker
1556*84e33947SAndroid Build Coastguard Worker } else if (resetting || !chppEnqueueTxDatagram(
1557*84e33947SAndroid Build Coastguard Worker context, CHPP_TRANSPORT_ERROR_NONE, buf, len)) {
1558*84e33947SAndroid Build Coastguard Worker uint8_t *handle = buf;
1559*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Resetting=%d. Discarding %" PRIuSIZE " bytes for H#%" PRIu8,
1560*84e33947SAndroid Build Coastguard Worker resetting, len, *handle);
1561*84e33947SAndroid Build Coastguard Worker
1562*84e33947SAndroid Build Coastguard Worker CHPP_FREE_AND_NULLIFY(buf);
1563*84e33947SAndroid Build Coastguard Worker
1564*84e33947SAndroid Build Coastguard Worker } else {
1565*84e33947SAndroid Build Coastguard Worker success = true;
1566*84e33947SAndroid Build Coastguard Worker }
1567*84e33947SAndroid Build Coastguard Worker
1568*84e33947SAndroid Build Coastguard Worker return success;
1569*84e33947SAndroid Build Coastguard Worker }
1570*84e33947SAndroid Build Coastguard Worker
1571*84e33947SAndroid Build Coastguard Worker // TODO(b/192359485): Consider removing this function, or making it more robust.
chppEnqueueTxErrorDatagram(struct ChppTransportState * context,enum ChppTransportErrorCode errorCode)1572*84e33947SAndroid Build Coastguard Worker void chppEnqueueTxErrorDatagram(struct ChppTransportState *context,
1573*84e33947SAndroid Build Coastguard Worker enum ChppTransportErrorCode errorCode) {
1574*84e33947SAndroid Build Coastguard Worker chppMutexLock(&context->mutex);
1575*84e33947SAndroid Build Coastguard Worker bool resetting = (context->resetState == CHPP_RESET_STATE_RESETTING);
1576*84e33947SAndroid Build Coastguard Worker if (resetting) {
1577*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Discarding app error 0x%" PRIx8 " (resetting)", errorCode);
1578*84e33947SAndroid Build Coastguard Worker } else {
1579*84e33947SAndroid Build Coastguard Worker switch (errorCode) {
1580*84e33947SAndroid Build Coastguard Worker case CHPP_TRANSPORT_ERROR_OOM: {
1581*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("App layer enqueueing CHPP_TRANSPORT_ERROR_OOM");
1582*84e33947SAndroid Build Coastguard Worker break;
1583*84e33947SAndroid Build Coastguard Worker }
1584*84e33947SAndroid Build Coastguard Worker case CHPP_TRANSPORT_ERROR_APPLAYER: {
1585*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("App layer enqueueing CHPP_TRANSPORT_ERROR_APPLAYER");
1586*84e33947SAndroid Build Coastguard Worker break;
1587*84e33947SAndroid Build Coastguard Worker }
1588*84e33947SAndroid Build Coastguard Worker default: {
1589*84e33947SAndroid Build Coastguard Worker // App layer should not invoke any other errors
1590*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_ASSERT_LOG(false, "App enqueueing invalid err=%" PRIu8,
1591*84e33947SAndroid Build Coastguard Worker errorCode);
1592*84e33947SAndroid Build Coastguard Worker }
1593*84e33947SAndroid Build Coastguard Worker }
1594*84e33947SAndroid Build Coastguard Worker chppEnqueueTxPacket(context, CHPP_ATTR_AND_ERROR_TO_PACKET_CODE(
1595*84e33947SAndroid Build Coastguard Worker CHPP_TRANSPORT_ATTR_NONE, errorCode));
1596*84e33947SAndroid Build Coastguard Worker }
1597*84e33947SAndroid Build Coastguard Worker chppMutexUnlock(&context->mutex);
1598*84e33947SAndroid Build Coastguard Worker }
1599*84e33947SAndroid Build Coastguard Worker
chppTransportGetTimeUntilNextDoWorkNs(struct ChppTransportState * context)1600*84e33947SAndroid Build Coastguard Worker uint64_t chppTransportGetTimeUntilNextDoWorkNs(
1601*84e33947SAndroid Build Coastguard Worker struct ChppTransportState *context) {
1602*84e33947SAndroid Build Coastguard Worker uint64_t currentTime = chppGetCurrentTimeNs();
1603*84e33947SAndroid Build Coastguard Worker // This function is called in the context of the transport worker thread.
1604*84e33947SAndroid Build Coastguard Worker // As we do not know if the transport is used in the context of a service
1605*84e33947SAndroid Build Coastguard Worker // or a client, we use the min of both timeouts.
1606*84e33947SAndroid Build Coastguard Worker uint64_t nextDoWorkTime =
1607*84e33947SAndroid Build Coastguard Worker MIN(context->appContext->nextClientRequestTimeoutNs,
1608*84e33947SAndroid Build Coastguard Worker context->appContext->nextServiceRequestTimeoutNs);
1609*84e33947SAndroid Build Coastguard Worker
1610*84e33947SAndroid Build Coastguard Worker if (context->txStatus.hasPacketsToSend ||
1611*84e33947SAndroid Build Coastguard Worker context->resetState == CHPP_RESET_STATE_RESETTING) {
1612*84e33947SAndroid Build Coastguard Worker nextDoWorkTime =
1613*84e33947SAndroid Build Coastguard Worker MIN(nextDoWorkTime, CHPP_TRANSPORT_TX_TIMEOUT_NS +
1614*84e33947SAndroid Build Coastguard Worker ((context->txStatus.lastTxTimeNs == 0)
1615*84e33947SAndroid Build Coastguard Worker ? currentTime
1616*84e33947SAndroid Build Coastguard Worker : context->txStatus.lastTxTimeNs));
1617*84e33947SAndroid Build Coastguard Worker }
1618*84e33947SAndroid Build Coastguard Worker
1619*84e33947SAndroid Build Coastguard Worker if (nextDoWorkTime == CHPP_TIME_MAX) {
1620*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("NextDoWork=n/a currentTime=%" PRIu64,
1621*84e33947SAndroid Build Coastguard Worker currentTime / CHPP_NSEC_PER_MSEC);
1622*84e33947SAndroid Build Coastguard Worker return CHPP_TRANSPORT_TIMEOUT_INFINITE;
1623*84e33947SAndroid Build Coastguard Worker }
1624*84e33947SAndroid Build Coastguard Worker
1625*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("NextDoWork=%" PRIu64 " currentTime=%" PRIu64 " delta=%" PRId64,
1626*84e33947SAndroid Build Coastguard Worker nextDoWorkTime / CHPP_NSEC_PER_MSEC,
1627*84e33947SAndroid Build Coastguard Worker currentTime / CHPP_NSEC_PER_MSEC,
1628*84e33947SAndroid Build Coastguard Worker (nextDoWorkTime > currentTime ? nextDoWorkTime - currentTime : 0) /
1629*84e33947SAndroid Build Coastguard Worker (int64_t)CHPP_NSEC_PER_MSEC);
1630*84e33947SAndroid Build Coastguard Worker
1631*84e33947SAndroid Build Coastguard Worker return nextDoWorkTime <= currentTime ? CHPP_TRANSPORT_TIMEOUT_IMMEDIATE
1632*84e33947SAndroid Build Coastguard Worker : nextDoWorkTime - currentTime;
1633*84e33947SAndroid Build Coastguard Worker }
1634*84e33947SAndroid Build Coastguard Worker
chppWorkThreadStart(struct ChppTransportState * context)1635*84e33947SAndroid Build Coastguard Worker void chppWorkThreadStart(struct ChppTransportState *context) {
1636*84e33947SAndroid Build Coastguard Worker chppTransportSendReset(context, CHPP_TRANSPORT_ATTR_RESET,
1637*84e33947SAndroid Build Coastguard Worker CHPP_TRANSPORT_ERROR_NONE);
1638*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("CHPP Work Thread started");
1639*84e33947SAndroid Build Coastguard Worker
1640*84e33947SAndroid Build Coastguard Worker uint32_t signals;
1641*84e33947SAndroid Build Coastguard Worker do {
1642*84e33947SAndroid Build Coastguard Worker uint64_t timeout = chppTransportGetTimeUntilNextDoWorkNs(context);
1643*84e33947SAndroid Build Coastguard Worker if (timeout == CHPP_TRANSPORT_TIMEOUT_IMMEDIATE) {
1644*84e33947SAndroid Build Coastguard Worker signals = chppNotifierGetSignal(&context->notifier);
1645*84e33947SAndroid Build Coastguard Worker } else if (timeout == CHPP_TRANSPORT_TIMEOUT_INFINITE) {
1646*84e33947SAndroid Build Coastguard Worker signals = chppNotifierWait(&context->notifier);
1647*84e33947SAndroid Build Coastguard Worker } else {
1648*84e33947SAndroid Build Coastguard Worker signals = chppNotifierTimedWait(&context->notifier, timeout);
1649*84e33947SAndroid Build Coastguard Worker }
1650*84e33947SAndroid Build Coastguard Worker
1651*84e33947SAndroid Build Coastguard Worker } while (chppWorkThreadHandleSignal(context, signals));
1652*84e33947SAndroid Build Coastguard Worker }
1653*84e33947SAndroid Build Coastguard Worker
chppWorkThreadHandleSignal(struct ChppTransportState * context,uint32_t signals)1654*84e33947SAndroid Build Coastguard Worker bool chppWorkThreadHandleSignal(struct ChppTransportState *context,
1655*84e33947SAndroid Build Coastguard Worker uint32_t signals) {
1656*84e33947SAndroid Build Coastguard Worker bool continueProcessing = false;
1657*84e33947SAndroid Build Coastguard Worker
1658*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_ENABLE_WORK_MONITOR
1659*84e33947SAndroid Build Coastguard Worker chppWorkMonitorPreProcess(&context->workMonitor);
1660*84e33947SAndroid Build Coastguard Worker #endif
1661*84e33947SAndroid Build Coastguard Worker
1662*84e33947SAndroid Build Coastguard Worker if (signals & CHPP_TRANSPORT_SIGNAL_EXIT) {
1663*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("CHPP Work Thread terminated");
1664*84e33947SAndroid Build Coastguard Worker } else {
1665*84e33947SAndroid Build Coastguard Worker continueProcessing = true;
1666*84e33947SAndroid Build Coastguard Worker if (signals == 0) {
1667*84e33947SAndroid Build Coastguard Worker // Triggered by timeout.
1668*84e33947SAndroid Build Coastguard Worker chppWorkHandleTimeout(context);
1669*84e33947SAndroid Build Coastguard Worker } else {
1670*84e33947SAndroid Build Coastguard Worker if (signals & CHPP_TRANSPORT_SIGNAL_EVENT) {
1671*84e33947SAndroid Build Coastguard Worker chppTransportDoWork(context);
1672*84e33947SAndroid Build Coastguard Worker }
1673*84e33947SAndroid Build Coastguard Worker if (signals & CHPP_TRANSPORT_SIGNAL_PLATFORM_MASK) {
1674*84e33947SAndroid Build Coastguard Worker context->linkApi->doWork(context->linkContext,
1675*84e33947SAndroid Build Coastguard Worker signals & CHPP_TRANSPORT_SIGNAL_PLATFORM_MASK);
1676*84e33947SAndroid Build Coastguard Worker }
1677*84e33947SAndroid Build Coastguard Worker }
1678*84e33947SAndroid Build Coastguard Worker }
1679*84e33947SAndroid Build Coastguard Worker
1680*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_ENABLE_WORK_MONITOR
1681*84e33947SAndroid Build Coastguard Worker chppWorkMonitorPostProcess(&context->workMonitor);
1682*84e33947SAndroid Build Coastguard Worker #endif
1683*84e33947SAndroid Build Coastguard Worker
1684*84e33947SAndroid Build Coastguard Worker return continueProcessing;
1685*84e33947SAndroid Build Coastguard Worker }
1686*84e33947SAndroid Build Coastguard Worker
1687*84e33947SAndroid Build Coastguard Worker /**
1688*84e33947SAndroid Build Coastguard Worker * Handle timeouts in the worker thread.
1689*84e33947SAndroid Build Coastguard Worker *
1690*84e33947SAndroid Build Coastguard Worker * Timeouts occurs when either:
1691*84e33947SAndroid Build Coastguard Worker * 1. There are packets to send and last packet send was more than
1692*84e33947SAndroid Build Coastguard Worker * CHPP_TRANSPORT_TX_TIMEOUT_NS ago
1693*84e33947SAndroid Build Coastguard Worker * 2. We haven't received a response to a request in time
1694*84e33947SAndroid Build Coastguard Worker * 3. We haven't received the reset ACK
1695*84e33947SAndroid Build Coastguard Worker *
1696*84e33947SAndroid Build Coastguard Worker * For 1 and 2, chppTransportDoWork should be called to respectively
1697*84e33947SAndroid Build Coastguard Worker * - Transmit the packet
1698*84e33947SAndroid Build Coastguard Worker * - Send a timeout response
1699*84e33947SAndroid Build Coastguard Worker */
chppWorkHandleTimeout(struct ChppTransportState * context)1700*84e33947SAndroid Build Coastguard Worker static void chppWorkHandleTimeout(struct ChppTransportState *context) {
1701*84e33947SAndroid Build Coastguard Worker const uint64_t currentTimeNs = chppGetCurrentTimeNs();
1702*84e33947SAndroid Build Coastguard Worker const bool isTxTimeout = currentTimeNs - context->txStatus.lastTxTimeNs >=
1703*84e33947SAndroid Build Coastguard Worker CHPP_TRANSPORT_TX_TIMEOUT_NS;
1704*84e33947SAndroid Build Coastguard Worker const bool isResetting = context->resetState == CHPP_RESET_STATE_RESETTING;
1705*84e33947SAndroid Build Coastguard Worker
1706*84e33947SAndroid Build Coastguard Worker // Call chppTransportDoWork for both TX and request timeouts.
1707*84e33947SAndroid Build Coastguard Worker if (isTxTimeout) {
1708*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("ACK timeout. Tx t=%" PRIu64 ", attempt %zu, isResetting=%d",
1709*84e33947SAndroid Build Coastguard Worker context->txStatus.lastTxTimeNs / CHPP_NSEC_PER_MSEC,
1710*84e33947SAndroid Build Coastguard Worker context->txStatus.txAttempts, isResetting);
1711*84e33947SAndroid Build Coastguard Worker chppTransportDoWork(context);
1712*84e33947SAndroid Build Coastguard Worker } else {
1713*84e33947SAndroid Build Coastguard Worker const uint64_t requestTimeoutNs =
1714*84e33947SAndroid Build Coastguard Worker MIN(context->appContext->nextClientRequestTimeoutNs,
1715*84e33947SAndroid Build Coastguard Worker context->appContext->nextServiceRequestTimeoutNs);
1716*84e33947SAndroid Build Coastguard Worker const bool isRequestTimeout = requestTimeoutNs <= currentTimeNs;
1717*84e33947SAndroid Build Coastguard Worker if (isRequestTimeout) {
1718*84e33947SAndroid Build Coastguard Worker chppTransportDoWork(context);
1719*84e33947SAndroid Build Coastguard Worker }
1720*84e33947SAndroid Build Coastguard Worker }
1721*84e33947SAndroid Build Coastguard Worker
1722*84e33947SAndroid Build Coastguard Worker if (isResetting && (currentTimeNs - context->resetTimeNs >=
1723*84e33947SAndroid Build Coastguard Worker CHPP_TRANSPORT_RESET_TIMEOUT_NS)) {
1724*84e33947SAndroid Build Coastguard Worker if (context->resetCount + 1 < CHPP_TRANSPORT_MAX_RESET) {
1725*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("RESET-ACK timeout; retrying");
1726*84e33947SAndroid Build Coastguard Worker context->resetCount++;
1727*84e33947SAndroid Build Coastguard Worker chppReset(context, CHPP_TRANSPORT_ATTR_RESET,
1728*84e33947SAndroid Build Coastguard Worker CHPP_TRANSPORT_ERROR_TIMEOUT);
1729*84e33947SAndroid Build Coastguard Worker } else {
1730*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("RESET-ACK timeout; giving up");
1731*84e33947SAndroid Build Coastguard Worker context->txStatus.txAttempts = 0;
1732*84e33947SAndroid Build Coastguard Worker context->resetState = CHPP_RESET_STATE_PERMANENT_FAILURE;
1733*84e33947SAndroid Build Coastguard Worker chppClearTxDatagramQueue(context);
1734*84e33947SAndroid Build Coastguard Worker }
1735*84e33947SAndroid Build Coastguard Worker }
1736*84e33947SAndroid Build Coastguard Worker }
1737*84e33947SAndroid Build Coastguard Worker
chppWorkThreadStop(struct ChppTransportState * context)1738*84e33947SAndroid Build Coastguard Worker void chppWorkThreadStop(struct ChppTransportState *context) {
1739*84e33947SAndroid Build Coastguard Worker chppNotifierSignal(&context->notifier, CHPP_TRANSPORT_SIGNAL_EXIT);
1740*84e33947SAndroid Build Coastguard Worker }
1741*84e33947SAndroid Build Coastguard Worker
chppLinkSendDoneCb(struct ChppTransportState * context,enum ChppLinkErrorCode error)1742*84e33947SAndroid Build Coastguard Worker void chppLinkSendDoneCb(struct ChppTransportState *context,
1743*84e33947SAndroid Build Coastguard Worker enum ChppLinkErrorCode error) {
1744*84e33947SAndroid Build Coastguard Worker if (error != CHPP_LINK_ERROR_NONE_SENT) {
1745*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Async send failure: %" PRIu8, error);
1746*84e33947SAndroid Build Coastguard Worker }
1747*84e33947SAndroid Build Coastguard Worker
1748*84e33947SAndroid Build Coastguard Worker chppMutexLock(&context->mutex);
1749*84e33947SAndroid Build Coastguard Worker
1750*84e33947SAndroid Build Coastguard Worker context->txStatus.linkBusy = false;
1751*84e33947SAndroid Build Coastguard Worker
1752*84e33947SAndroid Build Coastguard Worker // No need to free anything as link Tx buffer is static. Likewise, we
1753*84e33947SAndroid Build Coastguard Worker // keep linkBufferSize to assist testing.
1754*84e33947SAndroid Build Coastguard Worker
1755*84e33947SAndroid Build Coastguard Worker chppMutexUnlock(&context->mutex);
1756*84e33947SAndroid Build Coastguard Worker }
1757*84e33947SAndroid Build Coastguard Worker
chppDatagramProcessDoneCb(struct ChppTransportState * context,uint8_t * buf)1758*84e33947SAndroid Build Coastguard Worker void chppDatagramProcessDoneCb(struct ChppTransportState *context,
1759*84e33947SAndroid Build Coastguard Worker uint8_t *buf) {
1760*84e33947SAndroid Build Coastguard Worker UNUSED_VAR(context);
1761*84e33947SAndroid Build Coastguard Worker
1762*84e33947SAndroid Build Coastguard Worker CHPP_FREE_AND_NULLIFY(buf);
1763*84e33947SAndroid Build Coastguard Worker }
1764*84e33947SAndroid Build Coastguard Worker
chppRunTransportLoopback(struct ChppTransportState * context,uint8_t * buf,size_t len)1765*84e33947SAndroid Build Coastguard Worker uint8_t chppRunTransportLoopback(struct ChppTransportState *context,
1766*84e33947SAndroid Build Coastguard Worker uint8_t *buf, size_t len) {
1767*84e33947SAndroid Build Coastguard Worker UNUSED_VAR(buf);
1768*84e33947SAndroid Build Coastguard Worker UNUSED_VAR(len);
1769*84e33947SAndroid Build Coastguard Worker uint8_t result = CHPP_APP_ERROR_UNSUPPORTED;
1770*84e33947SAndroid Build Coastguard Worker context->loopbackResult = result;
1771*84e33947SAndroid Build Coastguard Worker
1772*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_CLIENT_ENABLED_TRANSPORT_LOOPBACK
1773*84e33947SAndroid Build Coastguard Worker result = CHPP_APP_ERROR_NONE;
1774*84e33947SAndroid Build Coastguard Worker context->loopbackResult = CHPP_APP_ERROR_UNSPECIFIED;
1775*84e33947SAndroid Build Coastguard Worker
1776*84e33947SAndroid Build Coastguard Worker if (len == 0 || len > chppTransportTxMtuSize(context)) {
1777*84e33947SAndroid Build Coastguard Worker result = CHPP_APP_ERROR_INVALID_LENGTH;
1778*84e33947SAndroid Build Coastguard Worker context->loopbackResult = result;
1779*84e33947SAndroid Build Coastguard Worker
1780*84e33947SAndroid Build Coastguard Worker } else if (context->txStatus.linkBusy) {
1781*84e33947SAndroid Build Coastguard Worker result = CHPP_APP_ERROR_BLOCKED;
1782*84e33947SAndroid Build Coastguard Worker context->loopbackResult = result;
1783*84e33947SAndroid Build Coastguard Worker
1784*84e33947SAndroid Build Coastguard Worker } else if (context->transportLoopbackData.payload != NULL) {
1785*84e33947SAndroid Build Coastguard Worker result = CHPP_APP_ERROR_BUSY;
1786*84e33947SAndroid Build Coastguard Worker context->loopbackResult = result;
1787*84e33947SAndroid Build Coastguard Worker
1788*84e33947SAndroid Build Coastguard Worker } else if ((context->transportLoopbackData.payload = chppMalloc(len)) ==
1789*84e33947SAndroid Build Coastguard Worker NULL) {
1790*84e33947SAndroid Build Coastguard Worker result = CHPP_APP_ERROR_OOM;
1791*84e33947SAndroid Build Coastguard Worker context->loopbackResult = result;
1792*84e33947SAndroid Build Coastguard Worker
1793*84e33947SAndroid Build Coastguard Worker } else {
1794*84e33947SAndroid Build Coastguard Worker uint8_t *linkTxBuffer = context->linkApi->getTxBuffer(context->linkContext);
1795*84e33947SAndroid Build Coastguard Worker context->transportLoopbackData.length = len;
1796*84e33947SAndroid Build Coastguard Worker memcpy(context->transportLoopbackData.payload, buf, len);
1797*84e33947SAndroid Build Coastguard Worker
1798*84e33947SAndroid Build Coastguard Worker context->txStatus.linkBusy = true;
1799*84e33947SAndroid Build Coastguard Worker context->linkBufferSize = 0;
1800*84e33947SAndroid Build Coastguard Worker const struct ChppLinkConfiguration linkConfig =
1801*84e33947SAndroid Build Coastguard Worker context->linkApi->getConfig(context->linkContext);
1802*84e33947SAndroid Build Coastguard Worker memset(linkTxBuffer, 0, linkConfig.txBufferLen);
1803*84e33947SAndroid Build Coastguard Worker context->linkBufferSize += chppAddPreamble(linkTxBuffer);
1804*84e33947SAndroid Build Coastguard Worker
1805*84e33947SAndroid Build Coastguard Worker struct ChppTransportHeader *txHeader =
1806*84e33947SAndroid Build Coastguard Worker (struct ChppTransportHeader *)&linkTxBuffer[context->linkBufferSize];
1807*84e33947SAndroid Build Coastguard Worker context->linkBufferSize += sizeof(*txHeader);
1808*84e33947SAndroid Build Coastguard Worker
1809*84e33947SAndroid Build Coastguard Worker txHeader->packetCode = CHPP_ATTR_AND_ERROR_TO_PACKET_CODE(
1810*84e33947SAndroid Build Coastguard Worker CHPP_TRANSPORT_ATTR_LOOPBACK_REQUEST, txHeader->packetCode);
1811*84e33947SAndroid Build Coastguard Worker
1812*84e33947SAndroid Build Coastguard Worker size_t payloadLen = MIN(len, chppTransportTxMtuSize(context));
1813*84e33947SAndroid Build Coastguard Worker txHeader->length = (uint16_t)payloadLen;
1814*84e33947SAndroid Build Coastguard Worker chppAppendToPendingTxPacket(context, buf, payloadLen);
1815*84e33947SAndroid Build Coastguard Worker
1816*84e33947SAndroid Build Coastguard Worker chppAddFooter(context);
1817*84e33947SAndroid Build Coastguard Worker
1818*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("Sending transport-loopback request (packet len=%" PRIuSIZE
1819*84e33947SAndroid Build Coastguard Worker ", payload len=%" PRIu16 ", asked len was %" PRIuSIZE ")",
1820*84e33947SAndroid Build Coastguard Worker context->linkBufferSize, txHeader->length, len);
1821*84e33947SAndroid Build Coastguard Worker enum ChppLinkErrorCode error = chppSendPendingPacket(context);
1822*84e33947SAndroid Build Coastguard Worker
1823*84e33947SAndroid Build Coastguard Worker if (error != CHPP_LINK_ERROR_NONE_QUEUED) {
1824*84e33947SAndroid Build Coastguard Worker // Either sent synchronously or an error has occurred
1825*84e33947SAndroid Build Coastguard Worker chppLinkSendDoneCb(context, error);
1826*84e33947SAndroid Build Coastguard Worker
1827*84e33947SAndroid Build Coastguard Worker if (error != CHPP_LINK_ERROR_NONE_SENT) {
1828*84e33947SAndroid Build Coastguard Worker // An error has occurred
1829*84e33947SAndroid Build Coastguard Worker CHPP_FREE_AND_NULLIFY(context->transportLoopbackData.payload);
1830*84e33947SAndroid Build Coastguard Worker context->transportLoopbackData.length = 0;
1831*84e33947SAndroid Build Coastguard Worker result = CHPP_APP_ERROR_UNSPECIFIED;
1832*84e33947SAndroid Build Coastguard Worker }
1833*84e33947SAndroid Build Coastguard Worker }
1834*84e33947SAndroid Build Coastguard Worker }
1835*84e33947SAndroid Build Coastguard Worker
1836*84e33947SAndroid Build Coastguard Worker if (result != CHPP_APP_ERROR_NONE) {
1837*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Trans-loopback failure: %" PRIu8, result);
1838*84e33947SAndroid Build Coastguard Worker }
1839*84e33947SAndroid Build Coastguard Worker #endif
1840*84e33947SAndroid Build Coastguard Worker return result;
1841*84e33947SAndroid Build Coastguard Worker }
1842*84e33947SAndroid Build Coastguard Worker
chppTransportSendReset(struct ChppTransportState * context,enum ChppTransportPacketAttributes resetType,enum ChppTransportErrorCode error)1843*84e33947SAndroid Build Coastguard Worker void chppTransportSendReset(struct ChppTransportState *context,
1844*84e33947SAndroid Build Coastguard Worker enum ChppTransportPacketAttributes resetType,
1845*84e33947SAndroid Build Coastguard Worker enum ChppTransportErrorCode error) {
1846*84e33947SAndroid Build Coastguard Worker // Make sure CHPP is in an initialized state
1847*84e33947SAndroid Build Coastguard Worker CHPP_ASSERT_LOG((context->txDatagramQueue.pending == 0 &&
1848*84e33947SAndroid Build Coastguard Worker context->txDatagramQueue.front == 0),
1849*84e33947SAndroid Build Coastguard Worker "Not init to send reset");
1850*84e33947SAndroid Build Coastguard Worker
1851*84e33947SAndroid Build Coastguard Worker struct ChppTransportConfiguration *config =
1852*84e33947SAndroid Build Coastguard Worker chppMalloc(sizeof(struct ChppTransportConfiguration));
1853*84e33947SAndroid Build Coastguard Worker if (config == NULL) {
1854*84e33947SAndroid Build Coastguard Worker CHPP_LOG_OOM();
1855*84e33947SAndroid Build Coastguard Worker } else {
1856*84e33947SAndroid Build Coastguard Worker // CHPP transport version
1857*84e33947SAndroid Build Coastguard Worker config->version.major = 1;
1858*84e33947SAndroid Build Coastguard Worker config->version.minor = 0;
1859*84e33947SAndroid Build Coastguard Worker config->version.patch = 0;
1860*84e33947SAndroid Build Coastguard Worker
1861*84e33947SAndroid Build Coastguard Worker config->reserved1 = 0;
1862*84e33947SAndroid Build Coastguard Worker config->reserved2 = 0;
1863*84e33947SAndroid Build Coastguard Worker config->reserved3 = 0;
1864*84e33947SAndroid Build Coastguard Worker
1865*84e33947SAndroid Build Coastguard Worker if (resetType == CHPP_TRANSPORT_ATTR_RESET_ACK) {
1866*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("Sending RESET-ACK");
1867*84e33947SAndroid Build Coastguard Worker chppSetResetComplete(context);
1868*84e33947SAndroid Build Coastguard Worker } else {
1869*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("Sending RESET");
1870*84e33947SAndroid Build Coastguard Worker }
1871*84e33947SAndroid Build Coastguard Worker
1872*84e33947SAndroid Build Coastguard Worker context->resetTimeNs = chppGetCurrentTimeNs();
1873*84e33947SAndroid Build Coastguard Worker
1874*84e33947SAndroid Build Coastguard Worker chppEnqueueTxDatagram(context,
1875*84e33947SAndroid Build Coastguard Worker CHPP_ATTR_AND_ERROR_TO_PACKET_CODE(resetType, error),
1876*84e33947SAndroid Build Coastguard Worker config, sizeof(*config));
1877*84e33947SAndroid Build Coastguard Worker }
1878*84e33947SAndroid Build Coastguard Worker }
1879*84e33947SAndroid Build Coastguard Worker
chppTransportTxMtuSize(const struct ChppTransportState * context)1880*84e33947SAndroid Build Coastguard Worker size_t chppTransportTxMtuSize(const struct ChppTransportState *context) {
1881*84e33947SAndroid Build Coastguard Worker const struct ChppLinkConfiguration linkConfig =
1882*84e33947SAndroid Build Coastguard Worker context->linkApi->getConfig(context->linkContext);
1883*84e33947SAndroid Build Coastguard Worker
1884*84e33947SAndroid Build Coastguard Worker return linkConfig.txBufferLen - CHPP_TRANSPORT_ENCODING_OVERHEAD_BYTES;
1885*84e33947SAndroid Build Coastguard Worker }
1886*84e33947SAndroid Build Coastguard Worker
chppTransportRxMtuSize(const struct ChppTransportState * context)1887*84e33947SAndroid Build Coastguard Worker size_t chppTransportRxMtuSize(const struct ChppTransportState *context) {
1888*84e33947SAndroid Build Coastguard Worker const struct ChppLinkConfiguration linkConfig =
1889*84e33947SAndroid Build Coastguard Worker context->linkApi->getConfig(context->linkContext);
1890*84e33947SAndroid Build Coastguard Worker
1891*84e33947SAndroid Build Coastguard Worker return linkConfig.rxBufferLen - CHPP_TRANSPORT_ENCODING_OVERHEAD_BYTES;
1892*84e33947SAndroid Build Coastguard Worker }