xref: /aosp_15_r20/system/chre/chpp/app.c (revision 84e339476a462649f82315436d70fd732297a399)
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 }