1*84e33947SAndroid Build Coastguard Worker /*
2*84e33947SAndroid Build Coastguard Worker * Copyright (C) 2020 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/app.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 <stdio.h>
24*84e33947SAndroid Build Coastguard Worker #include <string.h>
25*84e33947SAndroid Build Coastguard Worker
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/services.h"
29*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_CLIENT_ENABLED_LOOPBACK
30*84e33947SAndroid Build Coastguard Worker #include "chpp/clients/loopback.h"
31*84e33947SAndroid Build Coastguard Worker #endif
32*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_CLIENT_ENABLED_TIMESYNC
33*84e33947SAndroid Build Coastguard Worker #include "chpp/clients/timesync.h"
34*84e33947SAndroid Build Coastguard Worker #endif
35*84e33947SAndroid Build Coastguard Worker #include "chpp/log.h"
36*84e33947SAndroid Build Coastguard Worker #include "chpp/macros.h"
37*84e33947SAndroid Build Coastguard Worker #include "chpp/notifier.h"
38*84e33947SAndroid Build Coastguard Worker #include "chpp/pal_api.h"
39*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_CLIENT_ENABLED_VENDOR
40*84e33947SAndroid Build Coastguard Worker #include "chpp/platform/vendor_clients.h"
41*84e33947SAndroid Build Coastguard Worker #endif
42*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_SERVICE_ENABLED_VENDOR
43*84e33947SAndroid Build Coastguard Worker #include "chpp/platform/vendor_services.h"
44*84e33947SAndroid Build Coastguard Worker #endif
45*84e33947SAndroid Build Coastguard Worker #include "chpp/services.h"
46*84e33947SAndroid Build Coastguard Worker #include "chpp/services/discovery.h"
47*84e33947SAndroid Build Coastguard Worker #include "chpp/services/loopback.h"
48*84e33947SAndroid Build Coastguard Worker #include "chpp/services/nonhandle.h"
49*84e33947SAndroid Build Coastguard Worker #include "chpp/services/timesync.h"
50*84e33947SAndroid Build Coastguard Worker #include "chpp/time.h"
51*84e33947SAndroid Build Coastguard Worker
52*84e33947SAndroid Build Coastguard Worker /************************************************
53*84e33947SAndroid Build Coastguard Worker * Prototypes
54*84e33947SAndroid Build Coastguard Worker ***********************************************/
55*84e33947SAndroid Build Coastguard Worker
56*84e33947SAndroid Build Coastguard Worker static bool chppProcessPredefinedClientRequest(struct ChppAppState *context,
57*84e33947SAndroid Build Coastguard Worker uint8_t *buf, size_t len);
58*84e33947SAndroid Build Coastguard Worker static bool chppProcessPredefinedServiceResponse(struct ChppAppState *context,
59*84e33947SAndroid Build Coastguard Worker uint8_t *buf, size_t len);
60*84e33947SAndroid Build Coastguard Worker
61*84e33947SAndroid Build Coastguard Worker static bool chppDatagramLenIsOk(struct ChppAppState *context,
62*84e33947SAndroid Build Coastguard Worker const struct ChppAppHeader *rxHeader,
63*84e33947SAndroid Build Coastguard Worker size_t len);
64*84e33947SAndroid Build Coastguard Worker static ChppDispatchFunction *chppGetDispatchFunction(
65*84e33947SAndroid Build Coastguard Worker struct ChppAppState *context, uint8_t handle, enum ChppMessageType type);
66*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_CLIENT_ENABLED_DISCOVERY
67*84e33947SAndroid Build Coastguard Worker static ChppNotifierFunction *chppGetClientResetNotifierFunction(
68*84e33947SAndroid Build Coastguard Worker struct ChppAppState *context, uint8_t index);
69*84e33947SAndroid Build Coastguard Worker #endif // CHPP_CLIENT_ENABLED_DISCOVERY
70*84e33947SAndroid Build Coastguard Worker static ChppNotifierFunction *chppGetServiceResetNotifierFunction(
71*84e33947SAndroid Build Coastguard Worker struct ChppAppState *context, uint8_t index);
72*84e33947SAndroid Build Coastguard Worker static inline const struct ChppService *chppServiceOfHandle(
73*84e33947SAndroid Build Coastguard Worker struct ChppAppState *appContext, uint8_t handle);
74*84e33947SAndroid Build Coastguard Worker static inline const struct ChppClient *chppClientOfHandle(
75*84e33947SAndroid Build Coastguard Worker struct ChppAppState *appContext, uint8_t handle);
76*84e33947SAndroid Build Coastguard Worker static inline struct ChppEndpointState *chppServiceStateOfHandle(
77*84e33947SAndroid Build Coastguard Worker struct ChppAppState *appContext, uint8_t handle);
78*84e33947SAndroid Build Coastguard Worker static inline struct ChppEndpointState *chppClientStateOfHandle(
79*84e33947SAndroid Build Coastguard Worker struct ChppAppState *appContext, uint8_t handle);
80*84e33947SAndroid Build Coastguard Worker static struct ChppEndpointState *chppClientOrServiceStateOfHandle(
81*84e33947SAndroid Build Coastguard Worker struct ChppAppState *appContext, uint8_t handle, enum ChppMessageType type);
82*84e33947SAndroid Build Coastguard Worker
83*84e33947SAndroid Build Coastguard Worker static void chppProcessPredefinedHandleDatagram(struct ChppAppState *context,
84*84e33947SAndroid Build Coastguard Worker uint8_t *buf, size_t len);
85*84e33947SAndroid Build Coastguard Worker static void chppProcessNegotiatedHandleDatagram(struct ChppAppState *context,
86*84e33947SAndroid Build Coastguard Worker uint8_t *buf, size_t len);
87*84e33947SAndroid Build Coastguard Worker
88*84e33947SAndroid Build Coastguard Worker /************************************************
89*84e33947SAndroid Build Coastguard Worker * Private Functions
90*84e33947SAndroid Build Coastguard Worker ***********************************************/
91*84e33947SAndroid Build Coastguard Worker
92*84e33947SAndroid Build Coastguard Worker /**
93*84e33947SAndroid Build Coastguard Worker * Processes a client request that is determined to be for a predefined CHPP
94*84e33947SAndroid Build Coastguard Worker * service.
95*84e33947SAndroid Build Coastguard Worker *
96*84e33947SAndroid Build Coastguard Worker * @param context State of the app layer.
97*84e33947SAndroid Build Coastguard Worker * @param buf Input data. Cannot be null.
98*84e33947SAndroid Build Coastguard Worker * @param len Length of input data in bytes.
99*84e33947SAndroid Build Coastguard Worker *
100*84e33947SAndroid Build Coastguard Worker * @return False if handle is invalid. True otherwise.
101*84e33947SAndroid Build Coastguard Worker */
chppProcessPredefinedClientRequest(struct ChppAppState * context,uint8_t * buf,size_t len)102*84e33947SAndroid Build Coastguard Worker static bool chppProcessPredefinedClientRequest(struct ChppAppState *context,
103*84e33947SAndroid Build Coastguard Worker uint8_t *buf, size_t len) {
104*84e33947SAndroid Build Coastguard Worker const struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
105*84e33947SAndroid Build Coastguard Worker bool handleValid = true;
106*84e33947SAndroid Build Coastguard Worker bool dispatchResult = true;
107*84e33947SAndroid Build Coastguard Worker
108*84e33947SAndroid Build Coastguard Worker switch (rxHeader->handle) {
109*84e33947SAndroid Build Coastguard Worker case CHPP_HANDLE_LOOPBACK: {
110*84e33947SAndroid Build Coastguard Worker dispatchResult = chppDispatchLoopbackClientRequest(context, buf, len);
111*84e33947SAndroid Build Coastguard Worker break;
112*84e33947SAndroid Build Coastguard Worker }
113*84e33947SAndroid Build Coastguard Worker
114*84e33947SAndroid Build Coastguard Worker case CHPP_HANDLE_TIMESYNC: {
115*84e33947SAndroid Build Coastguard Worker dispatchResult = chppDispatchTimesyncClientRequest(context, buf, len);
116*84e33947SAndroid Build Coastguard Worker break;
117*84e33947SAndroid Build Coastguard Worker }
118*84e33947SAndroid Build Coastguard Worker
119*84e33947SAndroid Build Coastguard Worker case CHPP_HANDLE_DISCOVERY: {
120*84e33947SAndroid Build Coastguard Worker dispatchResult = chppDispatchDiscoveryClientRequest(context, buf, len);
121*84e33947SAndroid Build Coastguard Worker break;
122*84e33947SAndroid Build Coastguard Worker }
123*84e33947SAndroid Build Coastguard Worker
124*84e33947SAndroid Build Coastguard Worker default: {
125*84e33947SAndroid Build Coastguard Worker handleValid = false;
126*84e33947SAndroid Build Coastguard Worker }
127*84e33947SAndroid Build Coastguard Worker }
128*84e33947SAndroid Build Coastguard Worker
129*84e33947SAndroid Build Coastguard Worker if (dispatchResult == false) {
130*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("H#%" PRIu8 " unknown request. cmd=%#x, ID=%" PRIu8,
131*84e33947SAndroid Build Coastguard Worker rxHeader->handle, rxHeader->command, rxHeader->transaction);
132*84e33947SAndroid Build Coastguard Worker }
133*84e33947SAndroid Build Coastguard Worker
134*84e33947SAndroid Build Coastguard Worker return handleValid;
135*84e33947SAndroid Build Coastguard Worker }
136*84e33947SAndroid Build Coastguard Worker
137*84e33947SAndroid Build Coastguard Worker /**
138*84e33947SAndroid Build Coastguard Worker * Processes a service response that is determined to be for a predefined CHPP
139*84e33947SAndroid Build Coastguard Worker * client.
140*84e33947SAndroid Build Coastguard Worker *
141*84e33947SAndroid Build Coastguard Worker * @param context State of the app layer.
142*84e33947SAndroid Build Coastguard Worker * @param buf Input data. Cannot be null.
143*84e33947SAndroid Build Coastguard Worker * @param len Length of input data in bytes.
144*84e33947SAndroid Build Coastguard Worker *
145*84e33947SAndroid Build Coastguard Worker * @return False if handle is invalid. True otherwise.
146*84e33947SAndroid Build Coastguard Worker */
chppProcessPredefinedServiceResponse(struct ChppAppState * context,uint8_t * buf,size_t len)147*84e33947SAndroid Build Coastguard Worker static bool chppProcessPredefinedServiceResponse(struct ChppAppState *context,
148*84e33947SAndroid Build Coastguard Worker uint8_t *buf, size_t len) {
149*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(buf);
150*84e33947SAndroid Build Coastguard Worker // Possibly unused if compiling without the clients below enabled
151*84e33947SAndroid Build Coastguard Worker UNUSED_VAR(context);
152*84e33947SAndroid Build Coastguard Worker UNUSED_VAR(len);
153*84e33947SAndroid Build Coastguard Worker
154*84e33947SAndroid Build Coastguard Worker const struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
155*84e33947SAndroid Build Coastguard Worker bool handleValid = true;
156*84e33947SAndroid Build Coastguard Worker bool dispatchResult = true;
157*84e33947SAndroid Build Coastguard Worker
158*84e33947SAndroid Build Coastguard Worker switch (rxHeader->handle) {
159*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_CLIENT_ENABLED_LOOPBACK
160*84e33947SAndroid Build Coastguard Worker case CHPP_HANDLE_LOOPBACK: {
161*84e33947SAndroid Build Coastguard Worker dispatchResult = chppDispatchLoopbackServiceResponse(context, buf, len);
162*84e33947SAndroid Build Coastguard Worker break;
163*84e33947SAndroid Build Coastguard Worker }
164*84e33947SAndroid Build Coastguard Worker #endif // CHPP_CLIENT_ENABLED_LOOPBACK
165*84e33947SAndroid Build Coastguard Worker
166*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_CLIENT_ENABLED_TIMESYNC
167*84e33947SAndroid Build Coastguard Worker case CHPP_HANDLE_TIMESYNC: {
168*84e33947SAndroid Build Coastguard Worker dispatchResult = chppDispatchTimesyncServiceResponse(context, buf, len);
169*84e33947SAndroid Build Coastguard Worker break;
170*84e33947SAndroid Build Coastguard Worker }
171*84e33947SAndroid Build Coastguard Worker #endif // CHPP_CLIENT_ENABLED_TIMESYNC
172*84e33947SAndroid Build Coastguard Worker
173*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_CLIENT_ENABLED_DISCOVERY
174*84e33947SAndroid Build Coastguard Worker case CHPP_HANDLE_DISCOVERY: {
175*84e33947SAndroid Build Coastguard Worker dispatchResult = chppDispatchDiscoveryServiceResponse(context, buf, len);
176*84e33947SAndroid Build Coastguard Worker break;
177*84e33947SAndroid Build Coastguard Worker }
178*84e33947SAndroid Build Coastguard Worker #endif // CHPP_CLIENT_ENABLED_DISCOVERY
179*84e33947SAndroid Build Coastguard Worker
180*84e33947SAndroid Build Coastguard Worker default: {
181*84e33947SAndroid Build Coastguard Worker handleValid = false;
182*84e33947SAndroid Build Coastguard Worker }
183*84e33947SAndroid Build Coastguard Worker }
184*84e33947SAndroid Build Coastguard Worker
185*84e33947SAndroid Build Coastguard Worker if (dispatchResult == false) {
186*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("H#%" PRIu8 " unknown response. cmd=%#x, ID=%" PRIu8
187*84e33947SAndroid Build Coastguard Worker ", len=%" PRIuSIZE,
188*84e33947SAndroid Build Coastguard Worker rxHeader->handle, rxHeader->command, rxHeader->transaction, len);
189*84e33947SAndroid Build Coastguard Worker }
190*84e33947SAndroid Build Coastguard Worker
191*84e33947SAndroid Build Coastguard Worker return handleValid;
192*84e33947SAndroid Build Coastguard Worker }
193*84e33947SAndroid Build Coastguard Worker
194*84e33947SAndroid Build Coastguard Worker /**
195*84e33947SAndroid Build Coastguard Worker * Verifies if the length of a Rx Datagram from the transport layer is
196*84e33947SAndroid Build Coastguard Worker * sufficient for the associated service/client.
197*84e33947SAndroid Build Coastguard Worker *
198*84e33947SAndroid Build Coastguard Worker * @param context State of the app layer.
199*84e33947SAndroid Build Coastguard Worker * @param rxHeader The pointer to the datagram RX header.
200*84e33947SAndroid Build Coastguard Worker * @param len Length of the datagram in bytes.
201*84e33947SAndroid Build Coastguard Worker *
202*84e33947SAndroid Build Coastguard Worker * @return true if length is ok.
203*84e33947SAndroid Build Coastguard Worker */
chppDatagramLenIsOk(struct ChppAppState * context,const struct ChppAppHeader * rxHeader,size_t len)204*84e33947SAndroid Build Coastguard Worker static bool chppDatagramLenIsOk(struct ChppAppState *context,
205*84e33947SAndroid Build Coastguard Worker const struct ChppAppHeader *rxHeader,
206*84e33947SAndroid Build Coastguard Worker size_t len) {
207*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(context);
208*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(rxHeader);
209*84e33947SAndroid Build Coastguard Worker
210*84e33947SAndroid Build Coastguard Worker size_t minLen = SIZE_MAX;
211*84e33947SAndroid Build Coastguard Worker uint8_t handle = rxHeader->handle;
212*84e33947SAndroid Build Coastguard Worker
213*84e33947SAndroid Build Coastguard Worker if (handle < CHPP_HANDLE_NEGOTIATED_RANGE_START) { // Predefined
214*84e33947SAndroid Build Coastguard Worker switch (handle) {
215*84e33947SAndroid Build Coastguard Worker case CHPP_HANDLE_NONE:
216*84e33947SAndroid Build Coastguard Worker minLen = sizeof_member(struct ChppAppHeader, handle);
217*84e33947SAndroid Build Coastguard Worker break;
218*84e33947SAndroid Build Coastguard Worker
219*84e33947SAndroid Build Coastguard Worker case CHPP_HANDLE_LOOPBACK:
220*84e33947SAndroid Build Coastguard Worker minLen = sizeof_member(struct ChppAppHeader, handle) +
221*84e33947SAndroid Build Coastguard Worker sizeof_member(struct ChppAppHeader, type);
222*84e33947SAndroid Build Coastguard Worker break;
223*84e33947SAndroid Build Coastguard Worker
224*84e33947SAndroid Build Coastguard Worker case CHPP_HANDLE_TIMESYNC:
225*84e33947SAndroid Build Coastguard Worker case CHPP_HANDLE_DISCOVERY:
226*84e33947SAndroid Build Coastguard Worker minLen = sizeof(struct ChppAppHeader);
227*84e33947SAndroid Build Coastguard Worker break;
228*84e33947SAndroid Build Coastguard Worker
229*84e33947SAndroid Build Coastguard Worker default:
230*84e33947SAndroid Build Coastguard Worker // len remains SIZE_MAX
231*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Invalid H#%" PRIu8, handle);
232*84e33947SAndroid Build Coastguard Worker return false;
233*84e33947SAndroid Build Coastguard Worker }
234*84e33947SAndroid Build Coastguard Worker
235*84e33947SAndroid Build Coastguard Worker } else { // Negotiated
236*84e33947SAndroid Build Coastguard Worker enum ChppMessageType messageType =
237*84e33947SAndroid Build Coastguard Worker CHPP_APP_GET_MESSAGE_TYPE(rxHeader->type);
238*84e33947SAndroid Build Coastguard Worker
239*84e33947SAndroid Build Coastguard Worker switch (messageType) {
240*84e33947SAndroid Build Coastguard Worker case CHPP_MESSAGE_TYPE_CLIENT_REQUEST:
241*84e33947SAndroid Build Coastguard Worker case CHPP_MESSAGE_TYPE_CLIENT_RESPONSE:
242*84e33947SAndroid Build Coastguard Worker case CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION: {
243*84e33947SAndroid Build Coastguard Worker const struct ChppService *service =
244*84e33947SAndroid Build Coastguard Worker chppServiceOfHandle(context, handle);
245*84e33947SAndroid Build Coastguard Worker if (service != NULL) {
246*84e33947SAndroid Build Coastguard Worker minLen = service->minLength;
247*84e33947SAndroid Build Coastguard Worker }
248*84e33947SAndroid Build Coastguard Worker break;
249*84e33947SAndroid Build Coastguard Worker }
250*84e33947SAndroid Build Coastguard Worker case CHPP_MESSAGE_TYPE_SERVICE_RESPONSE:
251*84e33947SAndroid Build Coastguard Worker case CHPP_MESSAGE_TYPE_SERVICE_REQUEST:
252*84e33947SAndroid Build Coastguard Worker case CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION: {
253*84e33947SAndroid Build Coastguard Worker const struct ChppClient *client = chppClientOfHandle(context, handle);
254*84e33947SAndroid Build Coastguard Worker if (client != NULL) {
255*84e33947SAndroid Build Coastguard Worker minLen = client->minLength;
256*84e33947SAndroid Build Coastguard Worker }
257*84e33947SAndroid Build Coastguard Worker break;
258*84e33947SAndroid Build Coastguard Worker }
259*84e33947SAndroid Build Coastguard Worker default:
260*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Invalid type=%d or H#%" PRIu8, messageType, handle);
261*84e33947SAndroid Build Coastguard Worker return false;
262*84e33947SAndroid Build Coastguard Worker }
263*84e33947SAndroid Build Coastguard Worker }
264*84e33947SAndroid Build Coastguard Worker
265*84e33947SAndroid Build Coastguard Worker if (len < minLen) {
266*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Datagram len=%" PRIuSIZE " < %" PRIuSIZE " for H#%" PRIu8, len,
267*84e33947SAndroid Build Coastguard Worker minLen, handle);
268*84e33947SAndroid Build Coastguard Worker return false;
269*84e33947SAndroid Build Coastguard Worker }
270*84e33947SAndroid Build Coastguard Worker
271*84e33947SAndroid Build Coastguard Worker return true;
272*84e33947SAndroid Build Coastguard Worker }
273*84e33947SAndroid Build Coastguard Worker
274*84e33947SAndroid Build Coastguard Worker /**
275*84e33947SAndroid Build Coastguard Worker * Returns the dispatch function of a particular negotiated client/service
276*84e33947SAndroid Build Coastguard Worker * handle and message type.
277*84e33947SAndroid Build Coastguard Worker *
278*84e33947SAndroid Build Coastguard Worker * Returns null if it is unsupported by the service.
279*84e33947SAndroid Build Coastguard Worker *
280*84e33947SAndroid Build Coastguard Worker * @param context State of the app layer.
281*84e33947SAndroid Build Coastguard Worker * @param handle Handle number for the client/service.
282*84e33947SAndroid Build Coastguard Worker * @param type Message type.
283*84e33947SAndroid Build Coastguard Worker *
284*84e33947SAndroid Build Coastguard Worker * @return Pointer to a function that dispatches incoming datagrams for any
285*84e33947SAndroid Build Coastguard Worker * particular client/service.
286*84e33947SAndroid Build Coastguard Worker */
chppGetDispatchFunction(struct ChppAppState * context,uint8_t handle,enum ChppMessageType type)287*84e33947SAndroid Build Coastguard Worker static ChppDispatchFunction *chppGetDispatchFunction(
288*84e33947SAndroid Build Coastguard Worker struct ChppAppState *context, uint8_t handle, enum ChppMessageType type) {
289*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(context);
290*84e33947SAndroid Build Coastguard Worker // chppDatagramLenIsOk() has already confirmed that the handle # is valid.
291*84e33947SAndroid Build Coastguard Worker // Therefore, no additional checks are necessary for chppClientOfHandle(),
292*84e33947SAndroid Build Coastguard Worker // chppServiceOfHandle(), or chppClientOrServiceStateOfHandle().
293*84e33947SAndroid Build Coastguard Worker
294*84e33947SAndroid Build Coastguard Worker // Make sure the client is open before it can receive any message:
295*84e33947SAndroid Build Coastguard Worker switch (CHPP_APP_GET_MESSAGE_TYPE(type)) {
296*84e33947SAndroid Build Coastguard Worker case CHPP_MESSAGE_TYPE_SERVICE_RESPONSE:
297*84e33947SAndroid Build Coastguard Worker case CHPP_MESSAGE_TYPE_SERVICE_REQUEST:
298*84e33947SAndroid Build Coastguard Worker case CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION: {
299*84e33947SAndroid Build Coastguard Worker struct ChppEndpointState *clientState =
300*84e33947SAndroid Build Coastguard Worker chppClientStateOfHandle(context, handle);
301*84e33947SAndroid Build Coastguard Worker if (clientState->openState == CHPP_OPEN_STATE_CLOSED) {
302*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("RX service response but client closed");
303*84e33947SAndroid Build Coastguard Worker return NULL;
304*84e33947SAndroid Build Coastguard Worker }
305*84e33947SAndroid Build Coastguard Worker break;
306*84e33947SAndroid Build Coastguard Worker }
307*84e33947SAndroid Build Coastguard Worker default:
308*84e33947SAndroid Build Coastguard Worker // no check needed on the service side
309*84e33947SAndroid Build Coastguard Worker break;
310*84e33947SAndroid Build Coastguard Worker }
311*84e33947SAndroid Build Coastguard Worker
312*84e33947SAndroid Build Coastguard Worker switch (CHPP_APP_GET_MESSAGE_TYPE(type)) {
313*84e33947SAndroid Build Coastguard Worker case CHPP_MESSAGE_TYPE_CLIENT_REQUEST:
314*84e33947SAndroid Build Coastguard Worker return chppServiceOfHandle(context, handle)->requestDispatchFunctionPtr;
315*84e33947SAndroid Build Coastguard Worker case CHPP_MESSAGE_TYPE_SERVICE_RESPONSE:
316*84e33947SAndroid Build Coastguard Worker return chppClientOfHandle(context, handle)->responseDispatchFunctionPtr;
317*84e33947SAndroid Build Coastguard Worker case CHPP_MESSAGE_TYPE_SERVICE_REQUEST:
318*84e33947SAndroid Build Coastguard Worker return chppClientOfHandle(context, handle)->requestDispatchFunctionPtr;
319*84e33947SAndroid Build Coastguard Worker case CHPP_MESSAGE_TYPE_CLIENT_RESPONSE:
320*84e33947SAndroid Build Coastguard Worker return chppServiceOfHandle(context, handle)->responseDispatchFunctionPtr;
321*84e33947SAndroid Build Coastguard Worker case CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION:
322*84e33947SAndroid Build Coastguard Worker return chppServiceOfHandle(context, handle)
323*84e33947SAndroid Build Coastguard Worker ->notificationDispatchFunctionPtr;
324*84e33947SAndroid Build Coastguard Worker case CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION:
325*84e33947SAndroid Build Coastguard Worker return chppClientOfHandle(context, handle)
326*84e33947SAndroid Build Coastguard Worker ->notificationDispatchFunctionPtr;
327*84e33947SAndroid Build Coastguard Worker }
328*84e33947SAndroid Build Coastguard Worker
329*84e33947SAndroid Build Coastguard Worker return NULL;
330*84e33947SAndroid Build Coastguard Worker }
331*84e33947SAndroid Build Coastguard Worker
332*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_CLIENT_ENABLED_DISCOVERY
333*84e33947SAndroid Build Coastguard Worker /**
334*84e33947SAndroid Build Coastguard Worker * Returns the reset notification function pointer of a particular negotiated
335*84e33947SAndroid Build Coastguard Worker * client.
336*84e33947SAndroid Build Coastguard Worker *
337*84e33947SAndroid Build Coastguard Worker * Returns null for clients that do not need or support a reset notification.
338*84e33947SAndroid Build Coastguard Worker *
339*84e33947SAndroid Build Coastguard Worker * @param context State of the app layer.
340*84e33947SAndroid Build Coastguard Worker * @param index Index of the registered client.
341*84e33947SAndroid Build Coastguard Worker *
342*84e33947SAndroid Build Coastguard Worker * @return Pointer to the reset notification function.
343*84e33947SAndroid Build Coastguard Worker */
chppGetClientResetNotifierFunction(struct ChppAppState * context,uint8_t index)344*84e33947SAndroid Build Coastguard Worker static ChppNotifierFunction *chppGetClientResetNotifierFunction(
345*84e33947SAndroid Build Coastguard Worker struct ChppAppState *context, uint8_t index) {
346*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(context);
347*84e33947SAndroid Build Coastguard Worker return context->registeredClients[index]->resetNotifierFunctionPtr;
348*84e33947SAndroid Build Coastguard Worker }
349*84e33947SAndroid Build Coastguard Worker #endif // CHPP_CLIENT_ENABLED_DISCOVERY
350*84e33947SAndroid Build Coastguard Worker
351*84e33947SAndroid Build Coastguard Worker /**
352*84e33947SAndroid Build Coastguard Worker * Returns the reset function pointer of a particular registered service.
353*84e33947SAndroid Build Coastguard Worker *
354*84e33947SAndroid Build Coastguard Worker * Returns null for services that do not need or support a reset notification.
355*84e33947SAndroid Build Coastguard Worker *
356*84e33947SAndroid Build Coastguard Worker * @param context State of the app layer.
357*84e33947SAndroid Build Coastguard Worker * @param index Index of the registered service.
358*84e33947SAndroid Build Coastguard Worker *
359*84e33947SAndroid Build Coastguard Worker * @return Pointer to the reset function.
360*84e33947SAndroid Build Coastguard Worker */
chppGetServiceResetNotifierFunction(struct ChppAppState * context,uint8_t index)361*84e33947SAndroid Build Coastguard Worker ChppNotifierFunction *chppGetServiceResetNotifierFunction(
362*84e33947SAndroid Build Coastguard Worker struct ChppAppState *context, uint8_t index) {
363*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(context);
364*84e33947SAndroid Build Coastguard Worker return context->registeredServices[index]->resetNotifierFunctionPtr;
365*84e33947SAndroid Build Coastguard Worker }
366*84e33947SAndroid Build Coastguard Worker
367*84e33947SAndroid Build Coastguard Worker /**
368*84e33947SAndroid Build Coastguard Worker * Returns a pointer to the ChppService struct of the service matched to a
369*84e33947SAndroid Build Coastguard Worker * negotiated handle.
370*84e33947SAndroid Build Coastguard Worker *
371*84e33947SAndroid Build Coastguard Worker * Returns null if a service doesn't exist for the handle.
372*84e33947SAndroid Build Coastguard Worker *
373*84e33947SAndroid Build Coastguard Worker * @param context State of the app layer.
374*84e33947SAndroid Build Coastguard Worker * @param handle Handle number.
375*84e33947SAndroid Build Coastguard Worker *
376*84e33947SAndroid Build Coastguard Worker * @return Pointer to the ChppService struct of a particular service handle.
377*84e33947SAndroid Build Coastguard Worker */
chppServiceOfHandle(struct ChppAppState * context,uint8_t handle)378*84e33947SAndroid Build Coastguard Worker static inline const struct ChppService *chppServiceOfHandle(
379*84e33947SAndroid Build Coastguard Worker struct ChppAppState *context, uint8_t handle) {
380*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(context);
381*84e33947SAndroid Build Coastguard Worker uint8_t serviceIndex = CHPP_SERVICE_INDEX_OF_HANDLE(handle);
382*84e33947SAndroid Build Coastguard Worker if (serviceIndex < context->registeredServiceCount) {
383*84e33947SAndroid Build Coastguard Worker return context->registeredServices[serviceIndex];
384*84e33947SAndroid Build Coastguard Worker }
385*84e33947SAndroid Build Coastguard Worker
386*84e33947SAndroid Build Coastguard Worker return NULL;
387*84e33947SAndroid Build Coastguard Worker }
388*84e33947SAndroid Build Coastguard Worker
389*84e33947SAndroid Build Coastguard Worker /**
390*84e33947SAndroid Build Coastguard Worker * Returns a pointer to the ChppClient struct of the client matched to a
391*84e33947SAndroid Build Coastguard Worker * negotiated handle.
392*84e33947SAndroid Build Coastguard Worker *
393*84e33947SAndroid Build Coastguard Worker * Returns null if a client doesn't exist for the handle.
394*84e33947SAndroid Build Coastguard Worker *
395*84e33947SAndroid Build Coastguard Worker * @param context State of the app layer.
396*84e33947SAndroid Build Coastguard Worker * @param handle Handle number.
397*84e33947SAndroid Build Coastguard Worker *
398*84e33947SAndroid Build Coastguard Worker * @return Pointer to the ChppClient struct matched to a particular handle.
399*84e33947SAndroid Build Coastguard Worker */
chppClientOfHandle(struct ChppAppState * context,uint8_t handle)400*84e33947SAndroid Build Coastguard Worker static inline const struct ChppClient *chppClientOfHandle(
401*84e33947SAndroid Build Coastguard Worker struct ChppAppState *context, uint8_t handle) {
402*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(context);
403*84e33947SAndroid Build Coastguard Worker uint8_t serviceIndex = CHPP_SERVICE_INDEX_OF_HANDLE(handle);
404*84e33947SAndroid Build Coastguard Worker if (serviceIndex < context->discoveredServiceCount) {
405*84e33947SAndroid Build Coastguard Worker uint8_t clientIndex = context->clientIndexOfServiceIndex[serviceIndex];
406*84e33947SAndroid Build Coastguard Worker if (clientIndex < context->registeredClientCount) {
407*84e33947SAndroid Build Coastguard Worker return context->registeredClients[clientIndex];
408*84e33947SAndroid Build Coastguard Worker }
409*84e33947SAndroid Build Coastguard Worker }
410*84e33947SAndroid Build Coastguard Worker
411*84e33947SAndroid Build Coastguard Worker return NULL;
412*84e33947SAndroid Build Coastguard Worker }
413*84e33947SAndroid Build Coastguard Worker
414*84e33947SAndroid Build Coastguard Worker /**
415*84e33947SAndroid Build Coastguard Worker * Returns the service state for a given handle.
416*84e33947SAndroid Build Coastguard Worker *
417*84e33947SAndroid Build Coastguard Worker * The caller must pass a valid handle.
418*84e33947SAndroid Build Coastguard Worker *
419*84e33947SAndroid Build Coastguard Worker * @param context State of the app layer.
420*84e33947SAndroid Build Coastguard Worker * @param handle Handle number for the service.
421*84e33947SAndroid Build Coastguard Worker *
422*84e33947SAndroid Build Coastguard Worker * @return Pointer to a ChppEndpointState.
423*84e33947SAndroid Build Coastguard Worker */
chppServiceStateOfHandle(struct ChppAppState * context,uint8_t handle)424*84e33947SAndroid Build Coastguard Worker static inline struct ChppEndpointState *chppServiceStateOfHandle(
425*84e33947SAndroid Build Coastguard Worker struct ChppAppState *context, uint8_t handle) {
426*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(context);
427*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_ASSERT(CHPP_SERVICE_INDEX_OF_HANDLE(handle) <
428*84e33947SAndroid Build Coastguard Worker context->registeredServiceCount);
429*84e33947SAndroid Build Coastguard Worker
430*84e33947SAndroid Build Coastguard Worker const uint8_t serviceIdx = CHPP_SERVICE_INDEX_OF_HANDLE(handle);
431*84e33947SAndroid Build Coastguard Worker return context->registeredServiceStates[serviceIdx];
432*84e33947SAndroid Build Coastguard Worker }
433*84e33947SAndroid Build Coastguard Worker
434*84e33947SAndroid Build Coastguard Worker /**
435*84e33947SAndroid Build Coastguard Worker * Returns a pointer to the client state for a given handle.
436*84e33947SAndroid Build Coastguard Worker *
437*84e33947SAndroid Build Coastguard Worker * The caller must pass a valid handle.
438*84e33947SAndroid Build Coastguard Worker *
439*84e33947SAndroid Build Coastguard Worker * @param context State of the app layer.
440*84e33947SAndroid Build Coastguard Worker * @param handle Handle number for the service.
441*84e33947SAndroid Build Coastguard Worker *
442*84e33947SAndroid Build Coastguard Worker * @return Pointer to the endpoint state.
443*84e33947SAndroid Build Coastguard Worker */
chppClientStateOfHandle(struct ChppAppState * context,uint8_t handle)444*84e33947SAndroid Build Coastguard Worker static inline struct ChppEndpointState *chppClientStateOfHandle(
445*84e33947SAndroid Build Coastguard Worker struct ChppAppState *context, uint8_t handle) {
446*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(context);
447*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_ASSERT(CHPP_SERVICE_INDEX_OF_HANDLE(handle) <
448*84e33947SAndroid Build Coastguard Worker context->registeredClientCount);
449*84e33947SAndroid Build Coastguard Worker const uint8_t serviceIdx = CHPP_SERVICE_INDEX_OF_HANDLE(handle);
450*84e33947SAndroid Build Coastguard Worker const uint8_t clientIdx = context->clientIndexOfServiceIndex[serviceIdx];
451*84e33947SAndroid Build Coastguard Worker return context->registeredClientStates[clientIdx]->context;
452*84e33947SAndroid Build Coastguard Worker }
453*84e33947SAndroid Build Coastguard Worker
454*84e33947SAndroid Build Coastguard Worker /**
455*84e33947SAndroid Build Coastguard Worker * Returns a pointer to the client or service state for a given handle.
456*84e33947SAndroid Build Coastguard Worker *
457*84e33947SAndroid Build Coastguard Worker * The caller must pass a valid handle.
458*84e33947SAndroid Build Coastguard Worker *
459*84e33947SAndroid Build Coastguard Worker * @param appContext State of the app layer.
460*84e33947SAndroid Build Coastguard Worker * @param handle Handle number for the service.
461*84e33947SAndroid Build Coastguard Worker * @param type Message type (indicates if this is for a client or service).
462*84e33947SAndroid Build Coastguard Worker *
463*84e33947SAndroid Build Coastguard Worker * @return Pointer to the endpoint state (NULL if wrong type).
464*84e33947SAndroid Build Coastguard Worker */
chppClientOrServiceStateOfHandle(struct ChppAppState * appContext,uint8_t handle,enum ChppMessageType type)465*84e33947SAndroid Build Coastguard Worker static struct ChppEndpointState *chppClientOrServiceStateOfHandle(
466*84e33947SAndroid Build Coastguard Worker struct ChppAppState *appContext, uint8_t handle,
467*84e33947SAndroid Build Coastguard Worker enum ChppMessageType type) {
468*84e33947SAndroid Build Coastguard Worker switch (CHPP_APP_GET_MESSAGE_TYPE(type)) {
469*84e33947SAndroid Build Coastguard Worker case CHPP_MESSAGE_TYPE_CLIENT_REQUEST:
470*84e33947SAndroid Build Coastguard Worker case CHPP_MESSAGE_TYPE_CLIENT_RESPONSE:
471*84e33947SAndroid Build Coastguard Worker case CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION:
472*84e33947SAndroid Build Coastguard Worker return chppServiceStateOfHandle(appContext, handle);
473*84e33947SAndroid Build Coastguard Worker case CHPP_MESSAGE_TYPE_SERVICE_REQUEST:
474*84e33947SAndroid Build Coastguard Worker case CHPP_MESSAGE_TYPE_SERVICE_RESPONSE:
475*84e33947SAndroid Build Coastguard Worker case CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION:
476*84e33947SAndroid Build Coastguard Worker return chppClientStateOfHandle(appContext, handle);
477*84e33947SAndroid Build Coastguard Worker default:
478*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Unknown type=0x%" PRIx8 " (H#%" PRIu8 ")", type, handle);
479*84e33947SAndroid Build Coastguard Worker return NULL;
480*84e33947SAndroid Build Coastguard Worker }
481*84e33947SAndroid Build Coastguard Worker }
482*84e33947SAndroid Build Coastguard Worker
483*84e33947SAndroid Build Coastguard Worker /**
484*84e33947SAndroid Build Coastguard Worker * Processes a received datagram that is determined to be for a predefined CHPP
485*84e33947SAndroid Build Coastguard Worker * service. Responds with an error if unsuccessful.
486*84e33947SAndroid Build Coastguard Worker *
487*84e33947SAndroid Build Coastguard Worker * Predefined requests are only sent by the client side.
488*84e33947SAndroid Build Coastguard Worker * Predefined responses are only sent by the service side.
489*84e33947SAndroid Build Coastguard Worker *
490*84e33947SAndroid Build Coastguard Worker * @param context State of the app layer.
491*84e33947SAndroid Build Coastguard Worker * @param buf Input data. Cannot be null.
492*84e33947SAndroid Build Coastguard Worker * @param len Length of input data in bytes.
493*84e33947SAndroid Build Coastguard Worker */
chppProcessPredefinedHandleDatagram(struct ChppAppState * context,uint8_t * buf,size_t len)494*84e33947SAndroid Build Coastguard Worker static void chppProcessPredefinedHandleDatagram(struct ChppAppState *context,
495*84e33947SAndroid Build Coastguard Worker uint8_t *buf, size_t len) {
496*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(context);
497*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(buf);
498*84e33947SAndroid Build Coastguard Worker
499*84e33947SAndroid Build Coastguard Worker struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
500*84e33947SAndroid Build Coastguard Worker bool success = false;
501*84e33947SAndroid Build Coastguard Worker
502*84e33947SAndroid Build Coastguard Worker switch (CHPP_APP_GET_MESSAGE_TYPE(rxHeader->type)) {
503*84e33947SAndroid Build Coastguard Worker case CHPP_MESSAGE_TYPE_CLIENT_REQUEST: {
504*84e33947SAndroid Build Coastguard Worker success = chppProcessPredefinedClientRequest(context, buf, len);
505*84e33947SAndroid Build Coastguard Worker break;
506*84e33947SAndroid Build Coastguard Worker }
507*84e33947SAndroid Build Coastguard Worker case CHPP_MESSAGE_TYPE_SERVICE_RESPONSE: {
508*84e33947SAndroid Build Coastguard Worker success = chppProcessPredefinedServiceResponse(context, buf, len);
509*84e33947SAndroid Build Coastguard Worker break;
510*84e33947SAndroid Build Coastguard Worker }
511*84e33947SAndroid Build Coastguard Worker default:
512*84e33947SAndroid Build Coastguard Worker // Predefined client/services do not use
513*84e33947SAndroid Build Coastguard Worker // - notifications,
514*84e33947SAndroid Build Coastguard Worker // - service requests / client responses
515*84e33947SAndroid Build Coastguard Worker break;
516*84e33947SAndroid Build Coastguard Worker }
517*84e33947SAndroid Build Coastguard Worker
518*84e33947SAndroid Build Coastguard Worker if (!success) {
519*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("H#%" PRIu8 " undefined msg type=0x%" PRIx8 " (len=%" PRIuSIZE
520*84e33947SAndroid Build Coastguard Worker ", ID=%" PRIu8 ")",
521*84e33947SAndroid Build Coastguard Worker rxHeader->handle, rxHeader->type, len, rxHeader->transaction);
522*84e33947SAndroid Build Coastguard Worker chppEnqueueTxErrorDatagram(context->transportContext,
523*84e33947SAndroid Build Coastguard Worker CHPP_TRANSPORT_ERROR_APPLAYER);
524*84e33947SAndroid Build Coastguard Worker }
525*84e33947SAndroid Build Coastguard Worker }
526*84e33947SAndroid Build Coastguard Worker
527*84e33947SAndroid Build Coastguard Worker /**
528*84e33947SAndroid Build Coastguard Worker * Processes a received datagram that is determined to be for a negotiated CHPP
529*84e33947SAndroid Build Coastguard Worker * client or service.
530*84e33947SAndroid Build Coastguard Worker *
531*84e33947SAndroid Build Coastguard Worker * The datagram is processed by the dispatch function matching the datagram
532*84e33947SAndroid Build Coastguard Worker * type. @see ChppService and ChppClient.
533*84e33947SAndroid Build Coastguard Worker *
534*84e33947SAndroid Build Coastguard Worker * If a request dispatch function returns an error (anything different from
535*84e33947SAndroid Build Coastguard Worker * CHPP_APP_ERROR_NONE) then an error response is automatically sent back to the
536*84e33947SAndroid Build Coastguard Worker * remote endpoint.
537*84e33947SAndroid Build Coastguard Worker *
538*84e33947SAndroid Build Coastguard Worker * @param appContext State of the app layer.
539*84e33947SAndroid Build Coastguard Worker * @param buf Input data. Cannot be null.
540*84e33947SAndroid Build Coastguard Worker * @param len Length of input data in bytes.
541*84e33947SAndroid Build Coastguard Worker */
chppProcessNegotiatedHandleDatagram(struct ChppAppState * appContext,uint8_t * buf,size_t len)542*84e33947SAndroid Build Coastguard Worker static void chppProcessNegotiatedHandleDatagram(struct ChppAppState *appContext,
543*84e33947SAndroid Build Coastguard Worker uint8_t *buf, size_t len) {
544*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(appContext);
545*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(buf);
546*84e33947SAndroid Build Coastguard Worker
547*84e33947SAndroid Build Coastguard Worker const struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
548*84e33947SAndroid Build Coastguard Worker enum ChppMessageType messageType = CHPP_APP_GET_MESSAGE_TYPE(rxHeader->type);
549*84e33947SAndroid Build Coastguard Worker
550*84e33947SAndroid Build Coastguard Worker // Could be either the client or the service state depending on the message
551*84e33947SAndroid Build Coastguard Worker // type.
552*84e33947SAndroid Build Coastguard Worker struct ChppEndpointState *endpointState = chppClientOrServiceStateOfHandle(
553*84e33947SAndroid Build Coastguard Worker appContext, rxHeader->handle, messageType);
554*84e33947SAndroid Build Coastguard Worker if (endpointState == NULL) {
555*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("H#%" PRIu8 " missing ctx (msg=0x%" PRIx8 " len=%" PRIuSIZE
556*84e33947SAndroid Build Coastguard Worker ", ID=%" PRIu8 ")",
557*84e33947SAndroid Build Coastguard Worker rxHeader->handle, rxHeader->type, len, rxHeader->transaction);
558*84e33947SAndroid Build Coastguard Worker chppEnqueueTxErrorDatagram(appContext->transportContext,
559*84e33947SAndroid Build Coastguard Worker CHPP_TRANSPORT_ERROR_APPLAYER);
560*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_ASSERT(false);
561*84e33947SAndroid Build Coastguard Worker return;
562*84e33947SAndroid Build Coastguard Worker }
563*84e33947SAndroid Build Coastguard Worker
564*84e33947SAndroid Build Coastguard Worker ChppDispatchFunction *dispatchFunc =
565*84e33947SAndroid Build Coastguard Worker chppGetDispatchFunction(appContext, rxHeader->handle, messageType);
566*84e33947SAndroid Build Coastguard Worker if (dispatchFunc == NULL) {
567*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("H#%" PRIu8 " unsupported msg=0x%" PRIx8 " (len=%" PRIuSIZE
568*84e33947SAndroid Build Coastguard Worker ", ID=%" PRIu8 ")",
569*84e33947SAndroid Build Coastguard Worker rxHeader->handle, rxHeader->type, len, rxHeader->transaction);
570*84e33947SAndroid Build Coastguard Worker chppEnqueueTxErrorDatagram(appContext->transportContext,
571*84e33947SAndroid Build Coastguard Worker CHPP_TRANSPORT_ERROR_APPLAYER);
572*84e33947SAndroid Build Coastguard Worker return;
573*84e33947SAndroid Build Coastguard Worker }
574*84e33947SAndroid Build Coastguard Worker
575*84e33947SAndroid Build Coastguard Worker // All good. Dispatch datagram and possibly notify a waiting client
576*84e33947SAndroid Build Coastguard Worker enum ChppAppErrorCode error = dispatchFunc(endpointState->context, buf, len);
577*84e33947SAndroid Build Coastguard Worker
578*84e33947SAndroid Build Coastguard Worker if (error != CHPP_APP_ERROR_NONE) {
579*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("RX dispatch err=0x%" PRIx16 " H#%" PRIu8 " type=0x%" PRIx8
580*84e33947SAndroid Build Coastguard Worker " ID=%" PRIu8 " cmd=0x%" PRIx16 " len=%" PRIuSIZE,
581*84e33947SAndroid Build Coastguard Worker error, rxHeader->handle, rxHeader->type, rxHeader->transaction,
582*84e33947SAndroid Build Coastguard Worker rxHeader->command, len);
583*84e33947SAndroid Build Coastguard Worker
584*84e33947SAndroid Build Coastguard Worker // Requests require a dispatch failure response.
585*84e33947SAndroid Build Coastguard Worker if (messageType == CHPP_MESSAGE_TYPE_CLIENT_REQUEST ||
586*84e33947SAndroid Build Coastguard Worker messageType == CHPP_MESSAGE_TYPE_SERVICE_REQUEST) {
587*84e33947SAndroid Build Coastguard Worker struct ChppAppHeader *response =
588*84e33947SAndroid Build Coastguard Worker chppAllocResponseFixed(rxHeader, struct ChppAppHeader);
589*84e33947SAndroid Build Coastguard Worker if (response != NULL) {
590*84e33947SAndroid Build Coastguard Worker response->error = (uint8_t)error;
591*84e33947SAndroid Build Coastguard Worker chppEnqueueTxDatagramOrFail(appContext->transportContext, response,
592*84e33947SAndroid Build Coastguard Worker sizeof(*response));
593*84e33947SAndroid Build Coastguard Worker }
594*84e33947SAndroid Build Coastguard Worker }
595*84e33947SAndroid Build Coastguard Worker return;
596*84e33947SAndroid Build Coastguard Worker }
597*84e33947SAndroid Build Coastguard Worker
598*84e33947SAndroid Build Coastguard Worker // Datagram is a response.
599*84e33947SAndroid Build Coastguard Worker // Check for synchronous operation and notify waiting endpoint if needed.
600*84e33947SAndroid Build Coastguard Worker if (messageType == CHPP_MESSAGE_TYPE_SERVICE_RESPONSE ||
601*84e33947SAndroid Build Coastguard Worker messageType == CHPP_MESSAGE_TYPE_CLIENT_RESPONSE) {
602*84e33947SAndroid Build Coastguard Worker struct ChppSyncResponse *syncResponse = &endpointState->syncResponse;
603*84e33947SAndroid Build Coastguard Worker chppMutexLock(&syncResponse->mutex);
604*84e33947SAndroid Build Coastguard Worker syncResponse->ready = true;
605*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("Finished dispatching a response -> synchronous notification");
606*84e33947SAndroid Build Coastguard Worker chppConditionVariableSignal(&syncResponse->condVar);
607*84e33947SAndroid Build Coastguard Worker chppMutexUnlock(&syncResponse->mutex);
608*84e33947SAndroid Build Coastguard Worker }
609*84e33947SAndroid Build Coastguard Worker }
610*84e33947SAndroid Build Coastguard Worker
611*84e33947SAndroid Build Coastguard Worker /************************************************
612*84e33947SAndroid Build Coastguard Worker * Public Functions
613*84e33947SAndroid Build Coastguard Worker ***********************************************/
614*84e33947SAndroid Build Coastguard Worker
chppAppInit(struct ChppAppState * appContext,struct ChppTransportState * transportContext)615*84e33947SAndroid Build Coastguard Worker void chppAppInit(struct ChppAppState *appContext,
616*84e33947SAndroid Build Coastguard Worker struct ChppTransportState *transportContext) {
617*84e33947SAndroid Build Coastguard Worker // Default initialize all service/clients
618*84e33947SAndroid Build Coastguard Worker struct ChppClientServiceSet set;
619*84e33947SAndroid Build Coastguard Worker memset(&set, 0xff, sizeof(set)); // set all bits to 1
620*84e33947SAndroid Build Coastguard Worker
621*84e33947SAndroid Build Coastguard Worker chppAppInitWithClientServiceSet(appContext, transportContext, set);
622*84e33947SAndroid Build Coastguard Worker }
623*84e33947SAndroid Build Coastguard Worker
chppAppInitWithClientServiceSet(struct ChppAppState * appContext,struct ChppTransportState * transportContext,struct ChppClientServiceSet clientServiceSet)624*84e33947SAndroid Build Coastguard Worker void chppAppInitWithClientServiceSet(
625*84e33947SAndroid Build Coastguard Worker struct ChppAppState *appContext,
626*84e33947SAndroid Build Coastguard Worker struct ChppTransportState *transportContext,
627*84e33947SAndroid Build Coastguard Worker struct ChppClientServiceSet clientServiceSet) {
628*84e33947SAndroid Build Coastguard Worker CHPP_NOT_NULL(appContext);
629*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(transportContext);
630*84e33947SAndroid Build Coastguard Worker
631*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("App Init");
632*84e33947SAndroid Build Coastguard Worker
633*84e33947SAndroid Build Coastguard Worker memset(appContext, 0, sizeof(*appContext));
634*84e33947SAndroid Build Coastguard Worker
635*84e33947SAndroid Build Coastguard Worker appContext->clientServiceSet = clientServiceSet;
636*84e33947SAndroid Build Coastguard Worker appContext->transportContext = transportContext;
637*84e33947SAndroid Build Coastguard Worker appContext->nextClientRequestTimeoutNs = CHPP_TIME_MAX;
638*84e33947SAndroid Build Coastguard Worker appContext->nextServiceRequestTimeoutNs = CHPP_TIME_MAX;
639*84e33947SAndroid Build Coastguard Worker
640*84e33947SAndroid Build Coastguard Worker chppPalSystemApiInit(appContext);
641*84e33947SAndroid Build Coastguard Worker
642*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_SERVICE_ENABLED
643*84e33947SAndroid Build Coastguard Worker chppRegisterCommonServices(appContext);
644*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_SERVICE_ENABLED_VENDOR
645*84e33947SAndroid Build Coastguard Worker chppRegisterVendorServices(appContext);
646*84e33947SAndroid Build Coastguard Worker #endif
647*84e33947SAndroid Build Coastguard Worker #endif
648*84e33947SAndroid Build Coastguard Worker
649*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_CLIENT_ENABLED
650*84e33947SAndroid Build Coastguard Worker chppRegisterCommonClients(appContext);
651*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_CLIENT_ENABLED_VENDOR
652*84e33947SAndroid Build Coastguard Worker chppRegisterVendorClients(appContext);
653*84e33947SAndroid Build Coastguard Worker #endif
654*84e33947SAndroid Build Coastguard Worker chppInitBasicClients(appContext);
655*84e33947SAndroid Build Coastguard Worker #endif
656*84e33947SAndroid Build Coastguard Worker }
657*84e33947SAndroid Build Coastguard Worker
chppAppDeinit(struct ChppAppState * appContext)658*84e33947SAndroid Build Coastguard Worker void chppAppDeinit(struct ChppAppState *appContext) {
659*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("App deinit");
660*84e33947SAndroid Build Coastguard Worker
661*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_CLIENT_ENABLED
662*84e33947SAndroid Build Coastguard Worker chppDeinitMatchedClients(appContext);
663*84e33947SAndroid Build Coastguard Worker chppDeinitBasicClients(appContext);
664*84e33947SAndroid Build Coastguard Worker chppDeregisterCommonClients(appContext);
665*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_CLIENT_ENABLED_VENDOR
666*84e33947SAndroid Build Coastguard Worker chppDeregisterVendorClients(appContext);
667*84e33947SAndroid Build Coastguard Worker #endif
668*84e33947SAndroid Build Coastguard Worker #endif
669*84e33947SAndroid Build Coastguard Worker
670*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_SERVICE_ENABLED
671*84e33947SAndroid Build Coastguard Worker chppDeregisterCommonServices(appContext);
672*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_SERVICE_ENABLED_VENDOR
673*84e33947SAndroid Build Coastguard Worker chppDeregisterVendorServices(appContext);
674*84e33947SAndroid Build Coastguard Worker #endif
675*84e33947SAndroid Build Coastguard Worker #endif
676*84e33947SAndroid Build Coastguard Worker
677*84e33947SAndroid Build Coastguard Worker chppPalSystemApiDeinit(appContext);
678*84e33947SAndroid Build Coastguard Worker }
679*84e33947SAndroid Build Coastguard Worker
chppAppProcessRxDatagram(struct ChppAppState * context,uint8_t * buf,size_t len)680*84e33947SAndroid Build Coastguard Worker void chppAppProcessRxDatagram(struct ChppAppState *context, uint8_t *buf,
681*84e33947SAndroid Build Coastguard Worker size_t len) {
682*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(context);
683*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(buf);
684*84e33947SAndroid Build Coastguard Worker
685*84e33947SAndroid Build Coastguard Worker const struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
686*84e33947SAndroid Build Coastguard Worker
687*84e33947SAndroid Build Coastguard Worker if (len == 0) {
688*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_ASSERT_LOG(false, "App rx w/ len 0");
689*84e33947SAndroid Build Coastguard Worker
690*84e33947SAndroid Build Coastguard Worker } else if (len < sizeof(struct ChppAppHeader)) {
691*84e33947SAndroid Build Coastguard Worker uint8_t *handle = (uint8_t *)buf;
692*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("RX datagram len=%" PRIuSIZE " H#%" PRIu8, len, *handle);
693*84e33947SAndroid Build Coastguard Worker
694*84e33947SAndroid Build Coastguard Worker } else if (rxHeader->error != CHPP_APP_ERROR_NONE) {
695*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("RX datagram len=%" PRIuSIZE " H#%" PRIu8 " type=0x%" PRIx8
696*84e33947SAndroid Build Coastguard Worker " ID=%" PRIu8 " ERR=%" PRIu8 " cmd=0x%" PRIx16,
697*84e33947SAndroid Build Coastguard Worker len, rxHeader->handle, rxHeader->type, rxHeader->transaction,
698*84e33947SAndroid Build Coastguard Worker rxHeader->error, rxHeader->command);
699*84e33947SAndroid Build Coastguard Worker } else {
700*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("RX datagram len=%" PRIuSIZE " H#%" PRIu8 " type=0x%" PRIx8
701*84e33947SAndroid Build Coastguard Worker " ID=%" PRIu8 " err=%" PRIu8 " cmd=0x%" PRIx16,
702*84e33947SAndroid Build Coastguard Worker len, rxHeader->handle, rxHeader->type, rxHeader->transaction,
703*84e33947SAndroid Build Coastguard Worker rxHeader->error, rxHeader->command);
704*84e33947SAndroid Build Coastguard Worker }
705*84e33947SAndroid Build Coastguard Worker
706*84e33947SAndroid Build Coastguard Worker if (!chppDatagramLenIsOk(context, rxHeader, len)) {
707*84e33947SAndroid Build Coastguard Worker chppEnqueueTxErrorDatagram(context->transportContext,
708*84e33947SAndroid Build Coastguard Worker CHPP_TRANSPORT_ERROR_APPLAYER);
709*84e33947SAndroid Build Coastguard Worker
710*84e33947SAndroid Build Coastguard Worker } else {
711*84e33947SAndroid Build Coastguard Worker if (rxHeader->handle == CHPP_HANDLE_NONE) {
712*84e33947SAndroid Build Coastguard Worker chppDispatchNonHandle(context, buf, len);
713*84e33947SAndroid Build Coastguard Worker
714*84e33947SAndroid Build Coastguard Worker } else if (rxHeader->handle < CHPP_HANDLE_NEGOTIATED_RANGE_START) {
715*84e33947SAndroid Build Coastguard Worker chppProcessPredefinedHandleDatagram(context, buf, len);
716*84e33947SAndroid Build Coastguard Worker
717*84e33947SAndroid Build Coastguard Worker } else {
718*84e33947SAndroid Build Coastguard Worker chppProcessNegotiatedHandleDatagram(context, buf, len);
719*84e33947SAndroid Build Coastguard Worker }
720*84e33947SAndroid Build Coastguard Worker }
721*84e33947SAndroid Build Coastguard Worker
722*84e33947SAndroid Build Coastguard Worker chppDatagramProcessDoneCb(context->transportContext, buf);
723*84e33947SAndroid Build Coastguard Worker }
724*84e33947SAndroid Build Coastguard Worker
chppAppProcessReset(struct ChppAppState * context)725*84e33947SAndroid Build Coastguard Worker void chppAppProcessReset(struct ChppAppState *context) {
726*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(context);
727*84e33947SAndroid Build Coastguard Worker
728*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_CLIENT_ENABLED_DISCOVERY
729*84e33947SAndroid Build Coastguard Worker if (!context->isDiscoveryComplete) {
730*84e33947SAndroid Build Coastguard Worker chppInitiateDiscovery(context);
731*84e33947SAndroid Build Coastguard Worker
732*84e33947SAndroid Build Coastguard Worker } else {
733*84e33947SAndroid Build Coastguard Worker // Notify matched clients that a reset happened
734*84e33947SAndroid Build Coastguard Worker for (uint8_t i = 0; i < context->discoveredServiceCount; i++) {
735*84e33947SAndroid Build Coastguard Worker uint8_t clientIndex = context->clientIndexOfServiceIndex[i];
736*84e33947SAndroid Build Coastguard Worker if (clientIndex != CHPP_CLIENT_INDEX_NONE) {
737*84e33947SAndroid Build Coastguard Worker // Discovered service has a matched client
738*84e33947SAndroid Build Coastguard Worker ChppNotifierFunction *ResetNotifierFunction =
739*84e33947SAndroid Build Coastguard Worker chppGetClientResetNotifierFunction(context, clientIndex);
740*84e33947SAndroid Build Coastguard Worker
741*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("Client #%" PRIu8 " (H#%d) reset notifier found=%d",
742*84e33947SAndroid Build Coastguard Worker clientIndex, CHPP_SERVICE_HANDLE_OF_INDEX(i),
743*84e33947SAndroid Build Coastguard Worker (ResetNotifierFunction != NULL));
744*84e33947SAndroid Build Coastguard Worker
745*84e33947SAndroid Build Coastguard Worker if (ResetNotifierFunction != NULL) {
746*84e33947SAndroid Build Coastguard Worker ResetNotifierFunction(
747*84e33947SAndroid Build Coastguard Worker context->registeredClientStates[clientIndex]->context);
748*84e33947SAndroid Build Coastguard Worker }
749*84e33947SAndroid Build Coastguard Worker }
750*84e33947SAndroid Build Coastguard Worker }
751*84e33947SAndroid Build Coastguard Worker }
752*84e33947SAndroid Build Coastguard Worker #endif // CHPP_CLIENT_ENABLED_DISCOVERY
753*84e33947SAndroid Build Coastguard Worker
754*84e33947SAndroid Build Coastguard Worker // Notify registered services that a reset happened
755*84e33947SAndroid Build Coastguard Worker for (uint8_t i = 0; i < context->registeredServiceCount; i++) {
756*84e33947SAndroid Build Coastguard Worker ChppNotifierFunction *ResetNotifierFunction =
757*84e33947SAndroid Build Coastguard Worker chppGetServiceResetNotifierFunction(context, i);
758*84e33947SAndroid Build Coastguard Worker
759*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("Service #%" PRIu8 " (H#%d) reset notifier found=%d", i,
760*84e33947SAndroid Build Coastguard Worker CHPP_SERVICE_HANDLE_OF_INDEX(i), (ResetNotifierFunction != NULL));
761*84e33947SAndroid Build Coastguard Worker
762*84e33947SAndroid Build Coastguard Worker if (ResetNotifierFunction != NULL) {
763*84e33947SAndroid Build Coastguard Worker ResetNotifierFunction(context->registeredServiceStates[i]->context);
764*84e33947SAndroid Build Coastguard Worker }
765*84e33947SAndroid Build Coastguard Worker }
766*84e33947SAndroid Build Coastguard Worker
767*84e33947SAndroid Build Coastguard Worker #ifdef CHPP_CLIENT_ENABLED_TIMESYNC
768*84e33947SAndroid Build Coastguard Worker // Reinitialize time offset
769*84e33947SAndroid Build Coastguard Worker chppTimesyncClientReset(context);
770*84e33947SAndroid Build Coastguard Worker #endif
771*84e33947SAndroid Build Coastguard Worker }
772*84e33947SAndroid Build Coastguard Worker
chppUuidToStr(const uint8_t uuid[CHPP_SERVICE_UUID_LEN],char strOut[CHPP_SERVICE_UUID_STRING_LEN])773*84e33947SAndroid Build Coastguard Worker void chppUuidToStr(const uint8_t uuid[CHPP_SERVICE_UUID_LEN],
774*84e33947SAndroid Build Coastguard Worker char strOut[CHPP_SERVICE_UUID_STRING_LEN]) {
775*84e33947SAndroid Build Coastguard Worker snprintf(
776*84e33947SAndroid Build Coastguard Worker strOut, CHPP_SERVICE_UUID_STRING_LEN,
777*84e33947SAndroid Build Coastguard Worker "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
778*84e33947SAndroid Build Coastguard Worker uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
779*84e33947SAndroid Build Coastguard Worker uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],
780*84e33947SAndroid Build Coastguard Worker uuid[15]);
781*84e33947SAndroid Build Coastguard Worker }
782*84e33947SAndroid Build Coastguard Worker
chppAppErrorToChreError(uint8_t chppError)783*84e33947SAndroid Build Coastguard Worker uint8_t chppAppErrorToChreError(uint8_t chppError) {
784*84e33947SAndroid Build Coastguard Worker switch (chppError) {
785*84e33947SAndroid Build Coastguard Worker case CHPP_APP_ERROR_NONE:
786*84e33947SAndroid Build Coastguard Worker case CHPP_APP_ERROR_INVALID_ARG:
787*84e33947SAndroid Build Coastguard Worker case CHPP_APP_ERROR_BUSY:
788*84e33947SAndroid Build Coastguard Worker case CHPP_APP_ERROR_OOM:
789*84e33947SAndroid Build Coastguard Worker case CHPP_APP_ERROR_UNSUPPORTED:
790*84e33947SAndroid Build Coastguard Worker case CHPP_APP_ERROR_TIMEOUT:
791*84e33947SAndroid Build Coastguard Worker case CHPP_APP_ERROR_DISABLED:
792*84e33947SAndroid Build Coastguard Worker case CHPP_APP_ERROR_RATELIMITED: {
793*84e33947SAndroid Build Coastguard Worker // CHRE and CHPP error values are identical in these cases
794*84e33947SAndroid Build Coastguard Worker return chppError;
795*84e33947SAndroid Build Coastguard Worker }
796*84e33947SAndroid Build Coastguard Worker default: {
797*84e33947SAndroid Build Coastguard Worker return CHRE_ERROR;
798*84e33947SAndroid Build Coastguard Worker }
799*84e33947SAndroid Build Coastguard Worker }
800*84e33947SAndroid Build Coastguard Worker }
801*84e33947SAndroid Build Coastguard Worker
chppAppShortResponseErrorHandler(uint8_t * buf,size_t len,const char * responseName)802*84e33947SAndroid Build Coastguard Worker uint8_t chppAppShortResponseErrorHandler(uint8_t *buf, size_t len,
803*84e33947SAndroid Build Coastguard Worker const char *responseName) {
804*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(buf);
805*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(responseName);
806*84e33947SAndroid Build Coastguard Worker
807*84e33947SAndroid Build Coastguard Worker CHPP_ASSERT(len >= sizeof(struct ChppAppHeader));
808*84e33947SAndroid Build Coastguard Worker const struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
809*84e33947SAndroid Build Coastguard Worker
810*84e33947SAndroid Build Coastguard Worker if (rxHeader->error == CHPP_APP_ERROR_NONE) {
811*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("%s resp short len=%" PRIuSIZE, responseName, len);
812*84e33947SAndroid Build Coastguard Worker return CHRE_ERROR;
813*84e33947SAndroid Build Coastguard Worker }
814*84e33947SAndroid Build Coastguard Worker
815*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("%s resp short len=%" PRIuSIZE, responseName, len);
816*84e33947SAndroid Build Coastguard Worker return chppAppErrorToChreError(rxHeader->error);
817*84e33947SAndroid Build Coastguard Worker }
818*84e33947SAndroid Build Coastguard Worker
chppAllocNotification(uint8_t type,size_t len)819*84e33947SAndroid Build Coastguard Worker struct ChppAppHeader *chppAllocNotification(uint8_t type, size_t len) {
820*84e33947SAndroid Build Coastguard Worker CHPP_ASSERT(len >= sizeof(struct ChppAppHeader));
821*84e33947SAndroid Build Coastguard Worker CHPP_ASSERT(type == CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION ||
822*84e33947SAndroid Build Coastguard Worker type == CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION);
823*84e33947SAndroid Build Coastguard Worker
824*84e33947SAndroid Build Coastguard Worker struct ChppAppHeader *notification = chppMalloc(len);
825*84e33947SAndroid Build Coastguard Worker if (notification != NULL) {
826*84e33947SAndroid Build Coastguard Worker notification->type = type;
827*84e33947SAndroid Build Coastguard Worker notification->handle = CHPP_HANDLE_NONE;
828*84e33947SAndroid Build Coastguard Worker notification->transaction = 0;
829*84e33947SAndroid Build Coastguard Worker notification->error = CHPP_APP_ERROR_NONE;
830*84e33947SAndroid Build Coastguard Worker notification->command = CHPP_APP_COMMAND_NONE;
831*84e33947SAndroid Build Coastguard Worker } else {
832*84e33947SAndroid Build Coastguard Worker CHPP_LOG_OOM();
833*84e33947SAndroid Build Coastguard Worker }
834*84e33947SAndroid Build Coastguard Worker return notification;
835*84e33947SAndroid Build Coastguard Worker }
836*84e33947SAndroid Build Coastguard Worker
chppAllocRequest(uint8_t type,struct ChppEndpointState * endpointState,size_t len)837*84e33947SAndroid Build Coastguard Worker struct ChppAppHeader *chppAllocRequest(uint8_t type,
838*84e33947SAndroid Build Coastguard Worker struct ChppEndpointState *endpointState,
839*84e33947SAndroid Build Coastguard Worker size_t len) {
840*84e33947SAndroid Build Coastguard Worker CHPP_ASSERT(len >= sizeof(struct ChppAppHeader));
841*84e33947SAndroid Build Coastguard Worker CHPP_ASSERT(type == CHPP_MESSAGE_TYPE_CLIENT_REQUEST ||
842*84e33947SAndroid Build Coastguard Worker type == CHPP_MESSAGE_TYPE_SERVICE_REQUEST);
843*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(endpointState);
844*84e33947SAndroid Build Coastguard Worker
845*84e33947SAndroid Build Coastguard Worker struct ChppAppHeader *request = chppMalloc(len);
846*84e33947SAndroid Build Coastguard Worker if (request != NULL) {
847*84e33947SAndroid Build Coastguard Worker request->handle = endpointState->handle;
848*84e33947SAndroid Build Coastguard Worker request->type = type;
849*84e33947SAndroid Build Coastguard Worker request->transaction = endpointState->transaction;
850*84e33947SAndroid Build Coastguard Worker request->error = CHPP_APP_ERROR_NONE;
851*84e33947SAndroid Build Coastguard Worker request->command = CHPP_APP_COMMAND_NONE;
852*84e33947SAndroid Build Coastguard Worker
853*84e33947SAndroid Build Coastguard Worker endpointState->transaction++;
854*84e33947SAndroid Build Coastguard Worker } else {
855*84e33947SAndroid Build Coastguard Worker CHPP_LOG_OOM();
856*84e33947SAndroid Build Coastguard Worker }
857*84e33947SAndroid Build Coastguard Worker return request;
858*84e33947SAndroid Build Coastguard Worker }
859*84e33947SAndroid Build Coastguard Worker
chppAllocResponse(const struct ChppAppHeader * requestHeader,size_t len)860*84e33947SAndroid Build Coastguard Worker struct ChppAppHeader *chppAllocResponse(
861*84e33947SAndroid Build Coastguard Worker const struct ChppAppHeader *requestHeader, size_t len) {
862*84e33947SAndroid Build Coastguard Worker CHPP_ASSERT(len >= sizeof(struct ChppAppHeader));
863*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(requestHeader);
864*84e33947SAndroid Build Coastguard Worker uint8_t type = requestHeader->type;
865*84e33947SAndroid Build Coastguard Worker CHPP_ASSERT(type == CHPP_MESSAGE_TYPE_CLIENT_REQUEST ||
866*84e33947SAndroid Build Coastguard Worker type == CHPP_MESSAGE_TYPE_SERVICE_REQUEST);
867*84e33947SAndroid Build Coastguard Worker
868*84e33947SAndroid Build Coastguard Worker struct ChppAppHeader *response = chppMalloc(len);
869*84e33947SAndroid Build Coastguard Worker if (response != NULL) {
870*84e33947SAndroid Build Coastguard Worker *response = *requestHeader;
871*84e33947SAndroid Build Coastguard Worker response->type = type == CHPP_MESSAGE_TYPE_CLIENT_REQUEST
872*84e33947SAndroid Build Coastguard Worker ? CHPP_MESSAGE_TYPE_SERVICE_RESPONSE
873*84e33947SAndroid Build Coastguard Worker : CHPP_MESSAGE_TYPE_CLIENT_RESPONSE;
874*84e33947SAndroid Build Coastguard Worker response->error = CHPP_APP_ERROR_NONE;
875*84e33947SAndroid Build Coastguard Worker } else {
876*84e33947SAndroid Build Coastguard Worker CHPP_LOG_OOM();
877*84e33947SAndroid Build Coastguard Worker }
878*84e33947SAndroid Build Coastguard Worker return response;
879*84e33947SAndroid Build Coastguard Worker }
880*84e33947SAndroid Build Coastguard Worker
chppTimestampIncomingRequest(struct ChppIncomingRequestState * inReqState,const struct ChppAppHeader * requestHeader)881*84e33947SAndroid Build Coastguard Worker void chppTimestampIncomingRequest(struct ChppIncomingRequestState *inReqState,
882*84e33947SAndroid Build Coastguard Worker const struct ChppAppHeader *requestHeader) {
883*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(inReqState);
884*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(requestHeader);
885*84e33947SAndroid Build Coastguard Worker if (inReqState->responseTimeNs == CHPP_TIME_NONE &&
886*84e33947SAndroid Build Coastguard Worker inReqState->requestTimeNs != CHPP_TIME_NONE) {
887*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("RX dupe req t=%" PRIu64,
888*84e33947SAndroid Build Coastguard Worker inReqState->requestTimeNs / CHPP_NSEC_PER_MSEC);
889*84e33947SAndroid Build Coastguard Worker }
890*84e33947SAndroid Build Coastguard Worker inReqState->requestTimeNs = chppGetCurrentTimeNs();
891*84e33947SAndroid Build Coastguard Worker inReqState->responseTimeNs = CHPP_TIME_NONE;
892*84e33947SAndroid Build Coastguard Worker inReqState->transaction = requestHeader->transaction;
893*84e33947SAndroid Build Coastguard Worker }
894*84e33947SAndroid Build Coastguard Worker
chppTimestampOutgoingRequest(struct ChppAppState * appState,struct ChppOutgoingRequestState * outReqState,const struct ChppAppHeader * requestHeader,uint64_t timeoutNs)895*84e33947SAndroid Build Coastguard Worker void chppTimestampOutgoingRequest(struct ChppAppState *appState,
896*84e33947SAndroid Build Coastguard Worker struct ChppOutgoingRequestState *outReqState,
897*84e33947SAndroid Build Coastguard Worker const struct ChppAppHeader *requestHeader,
898*84e33947SAndroid Build Coastguard Worker uint64_t timeoutNs) {
899*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(appState);
900*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(outReqState);
901*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(requestHeader);
902*84e33947SAndroid Build Coastguard Worker enum ChppMessageType msgType = requestHeader->type;
903*84e33947SAndroid Build Coastguard Worker enum ChppEndpointType endpointType =
904*84e33947SAndroid Build Coastguard Worker msgType == CHPP_MESSAGE_TYPE_CLIENT_REQUEST ? CHPP_ENDPOINT_CLIENT
905*84e33947SAndroid Build Coastguard Worker : CHPP_ENDPOINT_SERVICE;
906*84e33947SAndroid Build Coastguard Worker
907*84e33947SAndroid Build Coastguard Worker CHPP_ASSERT(msgType == CHPP_MESSAGE_TYPE_CLIENT_REQUEST ||
908*84e33947SAndroid Build Coastguard Worker msgType == CHPP_MESSAGE_TYPE_SERVICE_REQUEST);
909*84e33947SAndroid Build Coastguard Worker
910*84e33947SAndroid Build Coastguard Worker // Hold the mutex to avoid concurrent read of a partially modified outReqState
911*84e33947SAndroid Build Coastguard Worker // structure by the RX thread
912*84e33947SAndroid Build Coastguard Worker chppMutexLock(&appState->transportContext->mutex);
913*84e33947SAndroid Build Coastguard Worker
914*84e33947SAndroid Build Coastguard Worker if (outReqState->requestState == CHPP_REQUEST_STATE_REQUEST_SENT) {
915*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Dupe req ID=%" PRIu8 " existing ID=%" PRIu8 " from t=%" PRIu64,
916*84e33947SAndroid Build Coastguard Worker requestHeader->transaction, outReqState->transaction,
917*84e33947SAndroid Build Coastguard Worker outReqState->requestTimeNs / CHPP_NSEC_PER_MSEC);
918*84e33947SAndroid Build Coastguard Worker
919*84e33947SAndroid Build Coastguard Worker // Clear a possible pending timeout from the previous request
920*84e33947SAndroid Build Coastguard Worker outReqState->responseTimeNs = CHPP_TIME_MAX;
921*84e33947SAndroid Build Coastguard Worker chppRecalculateNextTimeout(appState, endpointType);
922*84e33947SAndroid Build Coastguard Worker }
923*84e33947SAndroid Build Coastguard Worker
924*84e33947SAndroid Build Coastguard Worker outReqState->requestTimeNs = chppGetCurrentTimeNs();
925*84e33947SAndroid Build Coastguard Worker outReqState->requestState = CHPP_REQUEST_STATE_REQUEST_SENT;
926*84e33947SAndroid Build Coastguard Worker outReqState->transaction = requestHeader->transaction;
927*84e33947SAndroid Build Coastguard Worker
928*84e33947SAndroid Build Coastguard Worker uint64_t *nextRequestTimeoutNs =
929*84e33947SAndroid Build Coastguard Worker getNextRequestTimeoutNs(appState, endpointType);
930*84e33947SAndroid Build Coastguard Worker
931*84e33947SAndroid Build Coastguard Worker if (timeoutNs == CHPP_REQUEST_TIMEOUT_INFINITE) {
932*84e33947SAndroid Build Coastguard Worker outReqState->responseTimeNs = CHPP_TIME_MAX;
933*84e33947SAndroid Build Coastguard Worker
934*84e33947SAndroid Build Coastguard Worker } else {
935*84e33947SAndroid Build Coastguard Worker outReqState->responseTimeNs = timeoutNs + outReqState->requestTimeNs;
936*84e33947SAndroid Build Coastguard Worker
937*84e33947SAndroid Build Coastguard Worker *nextRequestTimeoutNs =
938*84e33947SAndroid Build Coastguard Worker MIN(*nextRequestTimeoutNs, outReqState->responseTimeNs);
939*84e33947SAndroid Build Coastguard Worker }
940*84e33947SAndroid Build Coastguard Worker
941*84e33947SAndroid Build Coastguard Worker chppMutexUnlock(&appState->transportContext->mutex);
942*84e33947SAndroid Build Coastguard Worker
943*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("Timestamp req ID=%" PRIu8 " at t=%" PRIu64 " timeout=%" PRIu64
944*84e33947SAndroid Build Coastguard Worker " (requested=%" PRIu64 "), next timeout=%" PRIu64,
945*84e33947SAndroid Build Coastguard Worker outReqState->transaction,
946*84e33947SAndroid Build Coastguard Worker outReqState->requestTimeNs / CHPP_NSEC_PER_MSEC,
947*84e33947SAndroid Build Coastguard Worker outReqState->responseTimeNs / CHPP_NSEC_PER_MSEC,
948*84e33947SAndroid Build Coastguard Worker timeoutNs / CHPP_NSEC_PER_MSEC,
949*84e33947SAndroid Build Coastguard Worker *nextRequestTimeoutNs / CHPP_NSEC_PER_MSEC);
950*84e33947SAndroid Build Coastguard Worker }
951*84e33947SAndroid Build Coastguard Worker
chppTimestampIncomingResponse(struct ChppAppState * appState,struct ChppOutgoingRequestState * outReqState,const struct ChppAppHeader * responseHeader)952*84e33947SAndroid Build Coastguard Worker bool chppTimestampIncomingResponse(struct ChppAppState *appState,
953*84e33947SAndroid Build Coastguard Worker struct ChppOutgoingRequestState *outReqState,
954*84e33947SAndroid Build Coastguard Worker const struct ChppAppHeader *responseHeader) {
955*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(appState);
956*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(outReqState);
957*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(responseHeader);
958*84e33947SAndroid Build Coastguard Worker
959*84e33947SAndroid Build Coastguard Worker uint8_t type = responseHeader->type;
960*84e33947SAndroid Build Coastguard Worker
961*84e33947SAndroid Build Coastguard Worker CHPP_ASSERT(type == CHPP_MESSAGE_TYPE_CLIENT_RESPONSE ||
962*84e33947SAndroid Build Coastguard Worker type == CHPP_MESSAGE_TYPE_SERVICE_RESPONSE);
963*84e33947SAndroid Build Coastguard Worker
964*84e33947SAndroid Build Coastguard Worker bool success = false;
965*84e33947SAndroid Build Coastguard Worker uint64_t responseTime = chppGetCurrentTimeNs();
966*84e33947SAndroid Build Coastguard Worker
967*84e33947SAndroid Build Coastguard Worker switch (outReqState->requestState) {
968*84e33947SAndroid Build Coastguard Worker case CHPP_REQUEST_STATE_NONE: {
969*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Resp with no req t=%" PRIu64,
970*84e33947SAndroid Build Coastguard Worker responseTime / CHPP_NSEC_PER_MSEC);
971*84e33947SAndroid Build Coastguard Worker break;
972*84e33947SAndroid Build Coastguard Worker }
973*84e33947SAndroid Build Coastguard Worker
974*84e33947SAndroid Build Coastguard Worker case CHPP_REQUEST_STATE_RESPONSE_RCV: {
975*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Extra resp at t=%" PRIu64 " for req t=%" PRIu64,
976*84e33947SAndroid Build Coastguard Worker responseTime / CHPP_NSEC_PER_MSEC,
977*84e33947SAndroid Build Coastguard Worker outReqState->requestTimeNs / CHPP_NSEC_PER_MSEC);
978*84e33947SAndroid Build Coastguard Worker break;
979*84e33947SAndroid Build Coastguard Worker }
980*84e33947SAndroid Build Coastguard Worker
981*84e33947SAndroid Build Coastguard Worker case CHPP_REQUEST_STATE_RESPONSE_TIMEOUT: {
982*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Late resp at t=%" PRIu64 " for req t=%" PRIu64,
983*84e33947SAndroid Build Coastguard Worker responseTime / CHPP_NSEC_PER_MSEC,
984*84e33947SAndroid Build Coastguard Worker outReqState->requestTimeNs / CHPP_NSEC_PER_MSEC);
985*84e33947SAndroid Build Coastguard Worker break;
986*84e33947SAndroid Build Coastguard Worker }
987*84e33947SAndroid Build Coastguard Worker
988*84e33947SAndroid Build Coastguard Worker case CHPP_REQUEST_STATE_REQUEST_SENT: {
989*84e33947SAndroid Build Coastguard Worker if (responseHeader->transaction != outReqState->transaction) {
990*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Invalid resp ID=%" PRIu8 " at t=%" PRIu64
991*84e33947SAndroid Build Coastguard Worker " expected=%" PRIu8,
992*84e33947SAndroid Build Coastguard Worker responseHeader->transaction,
993*84e33947SAndroid Build Coastguard Worker responseTime / CHPP_NSEC_PER_MSEC, outReqState->transaction);
994*84e33947SAndroid Build Coastguard Worker } else {
995*84e33947SAndroid Build Coastguard Worker outReqState->requestState = (responseTime > outReqState->responseTimeNs)
996*84e33947SAndroid Build Coastguard Worker ? CHPP_REQUEST_STATE_RESPONSE_TIMEOUT
997*84e33947SAndroid Build Coastguard Worker : CHPP_REQUEST_STATE_RESPONSE_RCV;
998*84e33947SAndroid Build Coastguard Worker success = true;
999*84e33947SAndroid Build Coastguard Worker
1000*84e33947SAndroid Build Coastguard Worker CHPP_LOGD(
1001*84e33947SAndroid Build Coastguard Worker "Timestamp resp ID=%" PRIu8 " req t=%" PRIu64 " resp t=%" PRIu64
1002*84e33947SAndroid Build Coastguard Worker " timeout t=%" PRIu64 " (RTT=%" PRIu64 ", timeout = %s)",
1003*84e33947SAndroid Build Coastguard Worker outReqState->transaction,
1004*84e33947SAndroid Build Coastguard Worker outReqState->requestTimeNs / CHPP_NSEC_PER_MSEC,
1005*84e33947SAndroid Build Coastguard Worker responseTime / CHPP_NSEC_PER_MSEC,
1006*84e33947SAndroid Build Coastguard Worker outReqState->responseTimeNs / CHPP_NSEC_PER_MSEC,
1007*84e33947SAndroid Build Coastguard Worker (responseTime - outReqState->requestTimeNs) / CHPP_NSEC_PER_MSEC,
1008*84e33947SAndroid Build Coastguard Worker (responseTime > outReqState->responseTimeNs) ? "yes" : "no");
1009*84e33947SAndroid Build Coastguard Worker }
1010*84e33947SAndroid Build Coastguard Worker break;
1011*84e33947SAndroid Build Coastguard Worker }
1012*84e33947SAndroid Build Coastguard Worker
1013*84e33947SAndroid Build Coastguard Worker default: {
1014*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_ASSERT_LOG(false, "Invalid req state");
1015*84e33947SAndroid Build Coastguard Worker }
1016*84e33947SAndroid Build Coastguard Worker }
1017*84e33947SAndroid Build Coastguard Worker
1018*84e33947SAndroid Build Coastguard Worker if (success) {
1019*84e33947SAndroid Build Coastguard Worker // When the received request is the next one that was expected
1020*84e33947SAndroid Build Coastguard Worker // to timeout we need to recompute the timeout considering the
1021*84e33947SAndroid Build Coastguard Worker // other pending requests.
1022*84e33947SAndroid Build Coastguard Worker enum ChppEndpointType endpointType =
1023*84e33947SAndroid Build Coastguard Worker type == CHPP_MESSAGE_TYPE_SERVICE_RESPONSE ? CHPP_ENDPOINT_CLIENT
1024*84e33947SAndroid Build Coastguard Worker : CHPP_ENDPOINT_SERVICE;
1025*84e33947SAndroid Build Coastguard Worker if (outReqState->responseTimeNs ==
1026*84e33947SAndroid Build Coastguard Worker *getNextRequestTimeoutNs(appState, endpointType)) {
1027*84e33947SAndroid Build Coastguard Worker chppRecalculateNextTimeout(appState, endpointType);
1028*84e33947SAndroid Build Coastguard Worker }
1029*84e33947SAndroid Build Coastguard Worker outReqState->responseTimeNs = responseTime;
1030*84e33947SAndroid Build Coastguard Worker }
1031*84e33947SAndroid Build Coastguard Worker return success;
1032*84e33947SAndroid Build Coastguard Worker }
1033*84e33947SAndroid Build Coastguard Worker
chppTimestampOutgoingResponse(struct ChppIncomingRequestState * inReqState)1034*84e33947SAndroid Build Coastguard Worker uint64_t chppTimestampOutgoingResponse(
1035*84e33947SAndroid Build Coastguard Worker struct ChppIncomingRequestState *inReqState) {
1036*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(inReqState);
1037*84e33947SAndroid Build Coastguard Worker
1038*84e33947SAndroid Build Coastguard Worker uint64_t previousResponseTime = inReqState->responseTimeNs;
1039*84e33947SAndroid Build Coastguard Worker inReqState->responseTimeNs = chppGetCurrentTimeNs();
1040*84e33947SAndroid Build Coastguard Worker return previousResponseTime;
1041*84e33947SAndroid Build Coastguard Worker }
1042*84e33947SAndroid Build Coastguard Worker
chppSendTimestampedResponseOrFail(struct ChppAppState * appState,struct ChppIncomingRequestState * inReqState,void * buf,size_t len)1043*84e33947SAndroid Build Coastguard Worker bool chppSendTimestampedResponseOrFail(
1044*84e33947SAndroid Build Coastguard Worker struct ChppAppState *appState, struct ChppIncomingRequestState *inReqState,
1045*84e33947SAndroid Build Coastguard Worker void *buf, size_t len) {
1046*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(appState);
1047*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(inReqState);
1048*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(buf);
1049*84e33947SAndroid Build Coastguard Worker uint64_t previousResponseTime = chppTimestampOutgoingResponse(inReqState);
1050*84e33947SAndroid Build Coastguard Worker
1051*84e33947SAndroid Build Coastguard Worker if (inReqState->requestTimeNs == CHPP_TIME_NONE) {
1052*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("TX response w/ no req t=%" PRIu64,
1053*84e33947SAndroid Build Coastguard Worker inReqState->responseTimeNs / CHPP_NSEC_PER_MSEC);
1054*84e33947SAndroid Build Coastguard Worker
1055*84e33947SAndroid Build Coastguard Worker } else if (previousResponseTime != CHPP_TIME_NONE) {
1056*84e33947SAndroid Build Coastguard Worker CHPP_LOGW("TX additional response t=%" PRIu64 " for req t=%" PRIu64,
1057*84e33947SAndroid Build Coastguard Worker inReqState->responseTimeNs / CHPP_NSEC_PER_MSEC,
1058*84e33947SAndroid Build Coastguard Worker inReqState->requestTimeNs / CHPP_NSEC_PER_MSEC);
1059*84e33947SAndroid Build Coastguard Worker
1060*84e33947SAndroid Build Coastguard Worker } else {
1061*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("Sending initial response at t=%" PRIu64
1062*84e33947SAndroid Build Coastguard Worker " for request at t=%" PRIu64 " (RTT=%" PRIu64 ")",
1063*84e33947SAndroid Build Coastguard Worker inReqState->responseTimeNs / CHPP_NSEC_PER_MSEC,
1064*84e33947SAndroid Build Coastguard Worker inReqState->requestTimeNs / CHPP_NSEC_PER_MSEC,
1065*84e33947SAndroid Build Coastguard Worker (inReqState->responseTimeNs - inReqState->requestTimeNs) /
1066*84e33947SAndroid Build Coastguard Worker CHPP_NSEC_PER_MSEC);
1067*84e33947SAndroid Build Coastguard Worker }
1068*84e33947SAndroid Build Coastguard Worker
1069*84e33947SAndroid Build Coastguard Worker return chppEnqueueTxDatagramOrFail(appState->transportContext, buf, len);
1070*84e33947SAndroid Build Coastguard Worker }
1071*84e33947SAndroid Build Coastguard Worker
chppSendTimestampedRequestOrFail(struct ChppEndpointState * endpointState,struct ChppOutgoingRequestState * outReqState,void * buf,size_t len,uint64_t timeoutNs)1072*84e33947SAndroid Build Coastguard Worker bool chppSendTimestampedRequestOrFail(
1073*84e33947SAndroid Build Coastguard Worker struct ChppEndpointState *endpointState,
1074*84e33947SAndroid Build Coastguard Worker struct ChppOutgoingRequestState *outReqState, void *buf, size_t len,
1075*84e33947SAndroid Build Coastguard Worker uint64_t timeoutNs) {
1076*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(outReqState);
1077*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(buf);
1078*84e33947SAndroid Build Coastguard Worker CHPP_ASSERT(len >= sizeof(struct ChppAppHeader));
1079*84e33947SAndroid Build Coastguard Worker
1080*84e33947SAndroid Build Coastguard Worker if (timeoutNs < CHPP_TRANSPORT_TX_TIMEOUT_NS) {
1081*84e33947SAndroid Build Coastguard Worker // The app layer sits above the transport layer.
1082*84e33947SAndroid Build Coastguard Worker // Request timeout (app layer) should be longer than the transport timeout.
1083*84e33947SAndroid Build Coastguard Worker CHPP_LOGW("Request timeout (%" PRIu64
1084*84e33947SAndroid Build Coastguard Worker "ns) should be longer than the transport timeout (%" PRIu64 "ns)",
1085*84e33947SAndroid Build Coastguard Worker timeoutNs, (uint64_t)CHPP_TRANSPORT_TX_TIMEOUT_NS);
1086*84e33947SAndroid Build Coastguard Worker }
1087*84e33947SAndroid Build Coastguard Worker
1088*84e33947SAndroid Build Coastguard Worker chppTimestampOutgoingRequest(endpointState->appContext, outReqState, buf,
1089*84e33947SAndroid Build Coastguard Worker timeoutNs);
1090*84e33947SAndroid Build Coastguard Worker endpointState->syncResponse.ready = false;
1091*84e33947SAndroid Build Coastguard Worker
1092*84e33947SAndroid Build Coastguard Worker bool success = chppEnqueueTxDatagramOrFail(
1093*84e33947SAndroid Build Coastguard Worker endpointState->appContext->transportContext, buf, len);
1094*84e33947SAndroid Build Coastguard Worker
1095*84e33947SAndroid Build Coastguard Worker // Failure to enqueue a TX datagram means that a request was known to be not
1096*84e33947SAndroid Build Coastguard Worker // transmitted. We explicitly set requestState to be in the NONE state, so
1097*84e33947SAndroid Build Coastguard Worker // that unintended app layer timeouts do not occur.
1098*84e33947SAndroid Build Coastguard Worker if (!success) {
1099*84e33947SAndroid Build Coastguard Worker outReqState->requestState = CHPP_REQUEST_STATE_NONE;
1100*84e33947SAndroid Build Coastguard Worker }
1101*84e33947SAndroid Build Coastguard Worker
1102*84e33947SAndroid Build Coastguard Worker return success;
1103*84e33947SAndroid Build Coastguard Worker }
1104*84e33947SAndroid Build Coastguard Worker
chppWaitForResponseWithTimeout(struct ChppSyncResponse * syncResponse,struct ChppOutgoingRequestState * outReqState,uint64_t timeoutNs)1105*84e33947SAndroid Build Coastguard Worker bool chppWaitForResponseWithTimeout(
1106*84e33947SAndroid Build Coastguard Worker struct ChppSyncResponse *syncResponse,
1107*84e33947SAndroid Build Coastguard Worker struct ChppOutgoingRequestState *outReqState, uint64_t timeoutNs) {
1108*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(syncResponse);
1109*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(outReqState);
1110*84e33947SAndroid Build Coastguard Worker
1111*84e33947SAndroid Build Coastguard Worker bool result = true;
1112*84e33947SAndroid Build Coastguard Worker
1113*84e33947SAndroid Build Coastguard Worker chppMutexLock(&syncResponse->mutex);
1114*84e33947SAndroid Build Coastguard Worker
1115*84e33947SAndroid Build Coastguard Worker while (result && !syncResponse->ready) {
1116*84e33947SAndroid Build Coastguard Worker result = chppConditionVariableTimedWait(&syncResponse->condVar,
1117*84e33947SAndroid Build Coastguard Worker &syncResponse->mutex, timeoutNs);
1118*84e33947SAndroid Build Coastguard Worker }
1119*84e33947SAndroid Build Coastguard Worker if (!syncResponse->ready) {
1120*84e33947SAndroid Build Coastguard Worker outReqState->requestState = CHPP_REQUEST_STATE_RESPONSE_TIMEOUT;
1121*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Response timeout after %" PRIu64 " ms",
1122*84e33947SAndroid Build Coastguard Worker timeoutNs / CHPP_NSEC_PER_MSEC);
1123*84e33947SAndroid Build Coastguard Worker result = false;
1124*84e33947SAndroid Build Coastguard Worker }
1125*84e33947SAndroid Build Coastguard Worker
1126*84e33947SAndroid Build Coastguard Worker chppMutexUnlock(&syncResponse->mutex);
1127*84e33947SAndroid Build Coastguard Worker
1128*84e33947SAndroid Build Coastguard Worker return result;
1129*84e33947SAndroid Build Coastguard Worker }
1130*84e33947SAndroid Build Coastguard Worker
getRegisteredEndpointState(struct ChppAppState * appState,uint8_t index,enum ChppEndpointType type)1131*84e33947SAndroid Build Coastguard Worker struct ChppEndpointState *getRegisteredEndpointState(
1132*84e33947SAndroid Build Coastguard Worker struct ChppAppState *appState, uint8_t index, enum ChppEndpointType type) {
1133*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(appState);
1134*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_ASSERT(index < getRegisteredEndpointCount(appState, type));
1135*84e33947SAndroid Build Coastguard Worker
1136*84e33947SAndroid Build Coastguard Worker return type == CHPP_ENDPOINT_CLIENT
1137*84e33947SAndroid Build Coastguard Worker ? appState->registeredClientStates[index]
1138*84e33947SAndroid Build Coastguard Worker : appState->registeredServiceStates[index];
1139*84e33947SAndroid Build Coastguard Worker }
1140*84e33947SAndroid Build Coastguard Worker
getRegisteredEndpointOutReqCount(struct ChppAppState * appState,uint8_t index,enum ChppEndpointType type)1141*84e33947SAndroid Build Coastguard Worker uint16_t getRegisteredEndpointOutReqCount(struct ChppAppState *appState,
1142*84e33947SAndroid Build Coastguard Worker uint8_t index,
1143*84e33947SAndroid Build Coastguard Worker enum ChppEndpointType type) {
1144*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(appState);
1145*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_ASSERT(index < getRegisteredEndpointCount(appState, type));
1146*84e33947SAndroid Build Coastguard Worker
1147*84e33947SAndroid Build Coastguard Worker return type == CHPP_ENDPOINT_CLIENT
1148*84e33947SAndroid Build Coastguard Worker ? appState->registeredClients[index]->outReqCount
1149*84e33947SAndroid Build Coastguard Worker : appState->registeredServices[index]->outReqCount;
1150*84e33947SAndroid Build Coastguard Worker }
1151*84e33947SAndroid Build Coastguard Worker
getRegisteredEndpointCount(struct ChppAppState * appState,enum ChppEndpointType type)1152*84e33947SAndroid Build Coastguard Worker uint8_t getRegisteredEndpointCount(struct ChppAppState *appState,
1153*84e33947SAndroid Build Coastguard Worker enum ChppEndpointType type) {
1154*84e33947SAndroid Build Coastguard Worker return type == CHPP_ENDPOINT_CLIENT ? appState->registeredClientCount
1155*84e33947SAndroid Build Coastguard Worker : appState->registeredServiceCount;
1156*84e33947SAndroid Build Coastguard Worker }
1157*84e33947SAndroid Build Coastguard Worker
chppRecalculateNextTimeout(struct ChppAppState * appState,enum ChppEndpointType type)1158*84e33947SAndroid Build Coastguard Worker void chppRecalculateNextTimeout(struct ChppAppState *appState,
1159*84e33947SAndroid Build Coastguard Worker enum ChppEndpointType type) {
1160*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(appState);
1161*84e33947SAndroid Build Coastguard Worker
1162*84e33947SAndroid Build Coastguard Worker uint64_t timeoutNs = CHPP_TIME_MAX;
1163*84e33947SAndroid Build Coastguard Worker
1164*84e33947SAndroid Build Coastguard Worker const uint8_t endpointCount = getRegisteredEndpointCount(appState, type);
1165*84e33947SAndroid Build Coastguard Worker
1166*84e33947SAndroid Build Coastguard Worker for (uint8_t endpointIdx = 0; endpointIdx < endpointCount; endpointIdx++) {
1167*84e33947SAndroid Build Coastguard Worker uint16_t reqCount =
1168*84e33947SAndroid Build Coastguard Worker getRegisteredEndpointOutReqCount(appState, endpointIdx, type);
1169*84e33947SAndroid Build Coastguard Worker struct ChppEndpointState *endpointState =
1170*84e33947SAndroid Build Coastguard Worker getRegisteredEndpointState(appState, endpointIdx, type);
1171*84e33947SAndroid Build Coastguard Worker struct ChppOutgoingRequestState *reqStates = endpointState->outReqStates;
1172*84e33947SAndroid Build Coastguard Worker for (uint16_t cmdIdx = 0; cmdIdx < reqCount; cmdIdx++) {
1173*84e33947SAndroid Build Coastguard Worker struct ChppOutgoingRequestState *reqState = &reqStates[cmdIdx];
1174*84e33947SAndroid Build Coastguard Worker
1175*84e33947SAndroid Build Coastguard Worker if (reqState->requestState == CHPP_REQUEST_STATE_REQUEST_SENT) {
1176*84e33947SAndroid Build Coastguard Worker timeoutNs = MIN(timeoutNs, reqState->responseTimeNs);
1177*84e33947SAndroid Build Coastguard Worker }
1178*84e33947SAndroid Build Coastguard Worker }
1179*84e33947SAndroid Build Coastguard Worker }
1180*84e33947SAndroid Build Coastguard Worker
1181*84e33947SAndroid Build Coastguard Worker CHPP_LOGD("nextReqTimeout=%" PRIu64, timeoutNs / CHPP_NSEC_PER_MSEC);
1182*84e33947SAndroid Build Coastguard Worker
1183*84e33947SAndroid Build Coastguard Worker if (type == CHPP_ENDPOINT_CLIENT) {
1184*84e33947SAndroid Build Coastguard Worker appState->nextClientRequestTimeoutNs = timeoutNs;
1185*84e33947SAndroid Build Coastguard Worker } else {
1186*84e33947SAndroid Build Coastguard Worker appState->nextServiceRequestTimeoutNs = timeoutNs;
1187*84e33947SAndroid Build Coastguard Worker }
1188*84e33947SAndroid Build Coastguard Worker }
1189*84e33947SAndroid Build Coastguard Worker
getNextRequestTimeoutNs(struct ChppAppState * appState,enum ChppEndpointType type)1190*84e33947SAndroid Build Coastguard Worker uint64_t *getNextRequestTimeoutNs(struct ChppAppState *appState,
1191*84e33947SAndroid Build Coastguard Worker enum ChppEndpointType type) {
1192*84e33947SAndroid Build Coastguard Worker return type == CHPP_ENDPOINT_CLIENT ? &appState->nextClientRequestTimeoutNs
1193*84e33947SAndroid Build Coastguard Worker : &appState->nextServiceRequestTimeoutNs;
1194*84e33947SAndroid Build Coastguard Worker }
1195*84e33947SAndroid Build Coastguard Worker
chppCloseOpenRequests(struct ChppEndpointState * endpointState,enum ChppEndpointType type,bool clearOnly)1196*84e33947SAndroid Build Coastguard Worker void chppCloseOpenRequests(struct ChppEndpointState *endpointState,
1197*84e33947SAndroid Build Coastguard Worker enum ChppEndpointType type, bool clearOnly) {
1198*84e33947SAndroid Build Coastguard Worker CHPP_DEBUG_NOT_NULL(endpointState);
1199*84e33947SAndroid Build Coastguard Worker
1200*84e33947SAndroid Build Coastguard Worker bool recalcNeeded = false;
1201*84e33947SAndroid Build Coastguard Worker
1202*84e33947SAndroid Build Coastguard Worker struct ChppAppState *appState = endpointState->appContext;
1203*84e33947SAndroid Build Coastguard Worker const uint8_t enpointIdx = endpointState->index;
1204*84e33947SAndroid Build Coastguard Worker const uint16_t cmdCount =
1205*84e33947SAndroid Build Coastguard Worker getRegisteredEndpointOutReqCount(appState, enpointIdx, type);
1206*84e33947SAndroid Build Coastguard Worker
1207*84e33947SAndroid Build Coastguard Worker for (uint16_t cmdIdx = 0; cmdIdx < cmdCount; cmdIdx++) {
1208*84e33947SAndroid Build Coastguard Worker if (endpointState->outReqStates[cmdIdx].requestState ==
1209*84e33947SAndroid Build Coastguard Worker CHPP_REQUEST_STATE_REQUEST_SENT) {
1210*84e33947SAndroid Build Coastguard Worker recalcNeeded = true;
1211*84e33947SAndroid Build Coastguard Worker
1212*84e33947SAndroid Build Coastguard Worker CHPP_LOGE("Closing open req #%" PRIu16 " clear %d", cmdIdx, clearOnly);
1213*84e33947SAndroid Build Coastguard Worker
1214*84e33947SAndroid Build Coastguard Worker if (clearOnly) {
1215*84e33947SAndroid Build Coastguard Worker endpointState->outReqStates[cmdIdx].requestState =
1216*84e33947SAndroid Build Coastguard Worker CHPP_REQUEST_STATE_RESPONSE_TIMEOUT;
1217*84e33947SAndroid Build Coastguard Worker } else {
1218*84e33947SAndroid Build Coastguard Worker struct ChppAppHeader *response =
1219*84e33947SAndroid Build Coastguard Worker chppMalloc(sizeof(struct ChppAppHeader));
1220*84e33947SAndroid Build Coastguard Worker if (response == NULL) {
1221*84e33947SAndroid Build Coastguard Worker CHPP_LOG_OOM();
1222*84e33947SAndroid Build Coastguard Worker } else {
1223*84e33947SAndroid Build Coastguard Worker // Simulate receiving a timeout response.
1224*84e33947SAndroid Build Coastguard Worker response->handle = endpointState->handle;
1225*84e33947SAndroid Build Coastguard Worker response->type = type == CHPP_ENDPOINT_CLIENT
1226*84e33947SAndroid Build Coastguard Worker ? CHPP_MESSAGE_TYPE_SERVICE_RESPONSE
1227*84e33947SAndroid Build Coastguard Worker : CHPP_MESSAGE_TYPE_CLIENT_RESPONSE;
1228*84e33947SAndroid Build Coastguard Worker response->transaction =
1229*84e33947SAndroid Build Coastguard Worker endpointState->outReqStates[cmdIdx].transaction;
1230*84e33947SAndroid Build Coastguard Worker response->error = CHPP_APP_ERROR_TIMEOUT;
1231*84e33947SAndroid Build Coastguard Worker response->command = cmdIdx;
1232*84e33947SAndroid Build Coastguard Worker
1233*84e33947SAndroid Build Coastguard Worker chppAppProcessRxDatagram(appState, (uint8_t *)response,
1234*84e33947SAndroid Build Coastguard Worker sizeof(struct ChppAppHeader));
1235*84e33947SAndroid Build Coastguard Worker }
1236*84e33947SAndroid Build Coastguard Worker }
1237*84e33947SAndroid Build Coastguard Worker }
1238*84e33947SAndroid Build Coastguard Worker }
1239*84e33947SAndroid Build Coastguard Worker if (recalcNeeded) {
1240*84e33947SAndroid Build Coastguard Worker chppRecalculateNextTimeout(appState, type);
1241*84e33947SAndroid Build Coastguard Worker }
1242*84e33947SAndroid Build Coastguard Worker }