• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "chpp/app.h"
18 
19 #include <inttypes.h>
20 #include <stdbool.h>
21 #include <stddef.h>
22 #include <stdint.h>
23 #include <stdio.h>
24 #include <string.h>
25 
26 #include "chpp/clients.h"
27 #include "chpp/clients/discovery.h"
28 #ifdef CHPP_CLIENT_ENABLED_LOOPBACK
29 #include "chpp/clients/loopback.h"
30 #endif
31 #ifdef CHPP_CLIENT_ENABLED_TIMESYNC
32 #include "chpp/clients/timesync.h"
33 #endif
34 #include "chpp/log.h"
35 #include "chpp/macros.h"
36 #include "chpp/notifier.h"
37 #include "chpp/pal_api.h"
38 #include "chpp/services.h"
39 #include "chpp/services/discovery.h"
40 #include "chpp/services/loopback.h"
41 #include "chpp/services/nonhandle.h"
42 #include "chpp/services/timesync.h"
43 #include "chre_api/chre/common.h"
44 
45 /************************************************
46  *  Prototypes
47  ***********************************************/
48 
49 static bool chppProcessPredefinedClientRequest(struct ChppAppState *context,
50                                                uint8_t *buf, size_t len);
51 static bool chppProcessPredefinedServiceResponse(struct ChppAppState *context,
52                                                  uint8_t *buf, size_t len);
53 static bool chppProcessPredefinedClientNotification(
54     struct ChppAppState *context, uint8_t *buf, size_t len);
55 static bool chppProcessPredefinedServiceNotification(
56     struct ChppAppState *context, uint8_t *buf, size_t len);
57 
58 static bool chppDatagramLenIsOk(struct ChppAppState *context,
59                                 struct ChppAppHeader *rxHeader, size_t len);
60 ChppDispatchFunction *chppGetDispatchFunction(struct ChppAppState *context,
61                                               uint8_t handle,
62                                               enum ChppMessageType type);
63 ChppNotifierFunction *chppGetClientResetNotifierFunction(
64     struct ChppAppState *context, uint8_t index);
65 ChppNotifierFunction *chppGetServiceResetNotifierFunction(
66     struct ChppAppState *context, uint8_t index);
67 static inline const struct ChppService *chppServiceOfHandle(
68     struct ChppAppState *appContext, uint8_t handle);
69 static inline const struct ChppClient *chppClientOfHandle(
70     struct ChppAppState *appContext, uint8_t handle);
71 static inline void *chppServiceContextOfHandle(struct ChppAppState *appContext,
72                                                uint8_t handle);
73 static inline void *chppClientContextOfHandle(struct ChppAppState *appContext,
74                                               uint8_t handle);
75 static void *chppClientServiceContextOfHandle(struct ChppAppState *appContext,
76                                               uint8_t handle,
77                                               enum ChppMessageType type);
78 
79 static void chppProcessPredefinedHandleDatagram(struct ChppAppState *context,
80                                                 uint8_t *buf, size_t len);
81 static void chppProcessNegotiatedHandleDatagram(struct ChppAppState *context,
82                                                 uint8_t *buf, size_t len);
83 
84 /************************************************
85  *  Private Functions
86  ***********************************************/
87 
88 /**
89  * Processes a client request that is determined to be for a predefined CHPP
90  * service.
91  *
92  * @param context Maintains status for each app layer instance.
93  * @param buf Input data. Cannot be null.
94  * @param len Length of input data in bytes.
95  *
96  * @return False if handle is invalid. True otherwise.
97  */
chppProcessPredefinedClientRequest(struct ChppAppState * context,uint8_t * buf,size_t len)98 static bool chppProcessPredefinedClientRequest(struct ChppAppState *context,
99                                                uint8_t *buf, size_t len) {
100   struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
101   bool handleValid = true;
102   bool dispatchResult = true;
103 
104   switch (rxHeader->handle) {
105     case CHPP_HANDLE_LOOPBACK: {
106       dispatchResult = chppDispatchLoopbackClientRequest(context, buf, len);
107       break;
108     }
109 
110     case CHPP_HANDLE_TIMESYNC: {
111       dispatchResult = chppDispatchTimesyncClientRequest(context, buf, len);
112       break;
113     }
114 
115     case CHPP_HANDLE_DISCOVERY: {
116       dispatchResult = chppDispatchDiscoveryClientRequest(context, buf, len);
117       break;
118     }
119 
120     default: {
121       handleValid = false;
122     }
123   }
124 
125   if (dispatchResult == false) {
126     CHPP_LOGE("H#%" PRIu8 " unknown request. cmd=%#x, ID=%" PRIu8,
127               rxHeader->handle, rxHeader->command, rxHeader->transaction);
128   }
129 
130   return handleValid;
131 }
132 
133 /**
134  * Processes a service response that is determined to be for a predefined CHPP
135  * client.
136  *
137  * @param context Maintains status for each app layer instance.
138  * @param buf Input data. Cannot be null.
139  * @param len Length of input data in bytes.
140  *
141  * @return False if handle is invalid. True otherwise.
142  */
chppProcessPredefinedServiceResponse(struct ChppAppState * context,uint8_t * buf,size_t len)143 static bool chppProcessPredefinedServiceResponse(struct ChppAppState *context,
144                                                  uint8_t *buf, size_t len) {
145   // Possibly unused if compiling without the clients below enabled
146   UNUSED_VAR(context);
147   UNUSED_VAR(buf);
148   UNUSED_VAR(len);
149 
150   struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
151   bool handleValid = true;
152   bool dispatchResult = true;
153 
154   switch (rxHeader->handle) {
155 #ifdef CHPP_CLIENT_ENABLED_LOOPBACK
156     case CHPP_HANDLE_LOOPBACK: {
157       dispatchResult = chppDispatchLoopbackServiceResponse(context, buf, len);
158       break;
159     }
160 #endif  // CHPP_CLIENT_ENABLED_LOOPBACK
161 
162 #ifdef CHPP_CLIENT_ENABLED_TIMESYNC
163     case CHPP_HANDLE_TIMESYNC: {
164       dispatchResult = chppDispatchTimesyncServiceResponse(context, buf, len);
165       break;
166     }
167 #endif  // CHPP_CLIENT_ENABLED_TIMESYNC
168 
169 #ifdef CHPP_CLIENT_ENABLED_DISCOVERY
170     case CHPP_HANDLE_DISCOVERY: {
171       dispatchResult = chppDispatchDiscoveryServiceResponse(context, buf, len);
172       break;
173     }
174 #endif  // CHPP_CLIENT_ENABLED_DISCOVERY
175 
176     default: {
177       handleValid = false;
178     }
179   }
180 
181   if (dispatchResult == false) {
182     CHPP_LOGE("H#%" PRIu8 " unknown response. cmd=%#x, ID=%" PRIu8
183               ", len=%" PRIuSIZE,
184               rxHeader->handle, rxHeader->command, rxHeader->transaction, len);
185   }
186 
187   return handleValid;
188 }
189 
190 /**
191  * Processes a client notification that is determined to be for a predefined
192  * CHPP service.
193  *
194  * @param context Maintains status for each app layer instance.
195  * @param buf Input data. Cannot be null.
196  * @param len Length of input data in bytes.
197  *
198  * @return False if handle is invalid. True otherwise.
199  */
chppProcessPredefinedClientNotification(struct ChppAppState * context,uint8_t * buf,size_t len)200 static bool chppProcessPredefinedClientNotification(
201     struct ChppAppState *context, uint8_t *buf, size_t len) {
202   UNUSED_VAR(context);
203   UNUSED_VAR(len);
204   UNUSED_VAR(buf);
205   // No predefined services support these.
206   return false;
207 }
208 
209 /**
210  * Processes a service notification that is determined to be for a predefined
211  * CHPP client.
212  *
213  * @param context Maintains status for each app layer instance.
214  * @param buf Input data. Cannot be null.
215  * @param len Length of input data in bytes.
216  *
217  * @return False if handle is invalid. True otherwise.
218  */
chppProcessPredefinedServiceNotification(struct ChppAppState * context,uint8_t * buf,size_t len)219 static bool chppProcessPredefinedServiceNotification(
220     struct ChppAppState *context, uint8_t *buf, size_t len) {
221   UNUSED_VAR(context);
222   UNUSED_VAR(len);
223   UNUSED_VAR(buf);
224   // No predefined clients support these.
225   return false;
226 }
227 
228 /**
229  * Verifies if the length of a Rx Datagram from the transport layer is
230  * sufficient for the associated service.
231  *
232  * @param context Maintains status for each app layer instance.
233  * @param rxHeader The pointer to the datagram RX header.
234  * @param len Length of the datagram in bytes.
235  *
236  * @return true if length is ok.
237  */
chppDatagramLenIsOk(struct ChppAppState * context,struct ChppAppHeader * rxHeader,size_t len)238 static bool chppDatagramLenIsOk(struct ChppAppState *context,
239                                 struct ChppAppHeader *rxHeader, size_t len) {
240   size_t minLen = SIZE_MAX;
241   uint8_t handle = rxHeader->handle;
242 
243   if (handle < CHPP_HANDLE_NEGOTIATED_RANGE_START) {  // Predefined
244     switch (handle) {
245       case CHPP_HANDLE_NONE:
246         minLen = sizeof_member(struct ChppAppHeader, handle);
247         break;
248 
249       case CHPP_HANDLE_LOOPBACK:
250         minLen = sizeof_member(struct ChppAppHeader, handle) +
251                  sizeof_member(struct ChppAppHeader, type);
252         break;
253 
254       case CHPP_HANDLE_TIMESYNC:
255       case CHPP_HANDLE_DISCOVERY:
256         minLen = sizeof(struct ChppAppHeader);
257         break;
258 
259       default:
260         // len remains SIZE_MAX
261         CHPP_LOGE("Invalid H#%" PRIu8, handle);
262     }
263 
264   } else {  // Negotiated
265     enum ChppMessageType messageType =
266         CHPP_APP_GET_MESSAGE_TYPE(rxHeader->type);
267 
268     switch (messageType) {
269       case CHPP_MESSAGE_TYPE_CLIENT_REQUEST:
270       case CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION: {
271         const struct ChppService *service =
272             chppServiceOfHandle(context, handle);
273         if (service != NULL) {
274           minLen = service->minLength;
275         }
276         break;
277       }
278       case CHPP_MESSAGE_TYPE_SERVICE_RESPONSE:
279       case CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION: {
280         const struct ChppClient *client = chppClientOfHandle(context, handle);
281         if (client != NULL) {
282           minLen = client->minLength;
283         }
284         break;
285       }
286       default: {
287         break;
288       }
289     }
290 
291     if (minLen == SIZE_MAX) {
292       CHPP_LOGE("Invalid type=%d or H#%" PRIu8, messageType, handle);
293     }
294   }
295 
296   if ((len < minLen) && (minLen != SIZE_MAX)) {
297     CHPP_LOGE("Datagram len=%" PRIuSIZE " < %" PRIuSIZE " for H#%" PRIu8, len,
298               minLen, handle);
299   }
300   return (len >= minLen) && (minLen != SIZE_MAX);
301 }
302 
303 /**
304  * Returns the dispatch function of a particular negotiated client/service
305  * handle and message type. This shall be null if it is unsupported by the
306  * service.
307  *
308  * @param context Maintains status for each app layer instance.
309  * @param handle Handle number for the client/service.
310  * @param type Message type.
311  *
312  * @return Pointer to a function that dispatches incoming datagrams for any
313  * particular client/service.
314  */
chppGetDispatchFunction(struct ChppAppState * context,uint8_t handle,enum ChppMessageType type)315 ChppDispatchFunction *chppGetDispatchFunction(struct ChppAppState *context,
316                                               uint8_t handle,
317                                               enum ChppMessageType type) {
318   // chppDatagramLenIsOk() has already confirmed that the handle # is valid.
319   // Therefore, no additional checks are necessary for chppClientOfHandle(),
320   // chppServiceOfHandle(), or chppClientServiceContextOfHandle().
321 
322   switch (CHPP_APP_GET_MESSAGE_TYPE(type)) {
323     case CHPP_MESSAGE_TYPE_CLIENT_REQUEST: {
324       return chppServiceOfHandle(context, handle)->requestDispatchFunctionPtr;
325     }
326     case CHPP_MESSAGE_TYPE_SERVICE_RESPONSE: {
327       struct ChppClientState *clientState =
328           (struct ChppClientState *)chppClientServiceContextOfHandle(
329               context, handle, type);
330       if (clientState->openState == CHPP_OPEN_STATE_CLOSED) {
331         CHPP_LOGE("RX service response but client closed");
332         break;
333       }
334       return chppClientOfHandle(context, handle)->responseDispatchFunctionPtr;
335     }
336     case CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION: {
337       return chppServiceOfHandle(context, handle)
338           ->notificationDispatchFunctionPtr;
339     }
340     case CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION: {
341       struct ChppClientState *clientState =
342           (struct ChppClientState *)chppClientServiceContextOfHandle(
343               context, handle, type);
344       if (clientState->openState == CHPP_OPEN_STATE_CLOSED) {
345         CHPP_LOGE("RX service notification but client closed");
346         break;
347       }
348       return chppClientOfHandle(context, handle)
349           ->notificationDispatchFunctionPtr;
350     }
351   }
352 
353   return NULL;
354 }
355 
356 /**
357  * Returns the reset notification function pointer of a particular negotiated
358  * client. The function pointer will be set to null by clients that do not need
359  * or support a reset notification.
360  *
361  * @param context Maintains status for each app layer instance.
362  * @param index Index of the registered client.
363  *
364  * @return Pointer to the reset notification function.
365  */
chppGetClientResetNotifierFunction(struct ChppAppState * context,uint8_t index)366 ChppNotifierFunction *chppGetClientResetNotifierFunction(
367     struct ChppAppState *context, uint8_t index) {
368   return context->registeredClients[index]->resetNotifierFunctionPtr;
369 }
370 
371 /**
372  * Returns the reset function pointer of a particular registered service. The
373  * function pointer will be set to null by services that do not need or support
374  * a reset notification.
375  *
376  * @param context Maintains status for each app layer instance.
377  * @param index Index of the registered service.
378  *
379  * @return Pointer to the reset function.
380  */
chppGetServiceResetNotifierFunction(struct ChppAppState * context,uint8_t index)381 ChppNotifierFunction *chppGetServiceResetNotifierFunction(
382     struct ChppAppState *context, uint8_t index) {
383   return context->registeredServices[index]->resetNotifierFunctionPtr;
384 }
385 
386 /**
387  * Returns a pointer to the ChppService struct of the service matched to a
388  * negotiated handle. Returns null if a service doesn't exist for the handle.
389  *
390  * @param context Maintains status for each app layer instance.
391  * @param handle Handle number.
392  *
393  * @return Pointer to the ChppService struct of a particular service handle.
394  */
chppServiceOfHandle(struct ChppAppState * context,uint8_t handle)395 static inline const struct ChppService *chppServiceOfHandle(
396     struct ChppAppState *context, uint8_t handle) {
397   uint8_t serviceIndex = CHPP_SERVICE_INDEX_OF_HANDLE(handle);
398   if (serviceIndex < context->registeredServiceCount) {
399     return context->registeredServices[serviceIndex];
400   }
401 
402   return NULL;
403 }
404 
405 /**
406  * Returns a pointer to the ChppClient struct of the client matched to a
407  * negotiated handle. Returns null if a client doesn't exist for the handle.
408  *
409  * @param context Maintains status for each app layer instance.
410  * @param handle Handle number.
411  *
412  * @return Pointer to the ChppClient struct matched to a particular handle.
413  */
chppClientOfHandle(struct ChppAppState * context,uint8_t handle)414 static inline const struct ChppClient *chppClientOfHandle(
415     struct ChppAppState *context, uint8_t handle) {
416   uint8_t serviceIndex = CHPP_SERVICE_INDEX_OF_HANDLE(handle);
417   if (serviceIndex < context->discoveredServiceCount) {
418     uint8_t clientIndex = context->clientIndexOfServiceIndex[serviceIndex];
419     if (clientIndex < context->registeredClientCount) {
420       return context->registeredClients[clientIndex];
421     }
422   }
423 
424   return NULL;
425 }
426 
427 /**
428  * Returns a pointer to the service struct of a particular negotiated service
429  * handle.
430  * It is up to the caller to ensure the handle number is valid.
431  *
432  * @param context Maintains status for each app layer instance.
433  * @param handle Handle number for the service.
434  *
435  * @return Pointer to the context struct of the service.
436  */
chppServiceContextOfHandle(struct ChppAppState * context,uint8_t handle)437 static inline void *chppServiceContextOfHandle(struct ChppAppState *context,
438                                                uint8_t handle) {
439   CHPP_DEBUG_ASSERT(CHPP_SERVICE_INDEX_OF_HANDLE(handle) <
440                     context->registeredServiceCount);
441   return context
442       ->registeredServiceContexts[CHPP_SERVICE_INDEX_OF_HANDLE(handle)];
443 }
444 
445 /**
446  * Returns a pointer to the client struct of a particular negotiated client
447  * handle.
448  * It is up to the caller to ensure the handle number is valid.
449  *
450  * @param context Maintains status for each app layer instance.
451  * @param handle Handle number for the service.
452  *
453  * @return Pointer to the ChppService struct of the client.
454  */
chppClientContextOfHandle(struct ChppAppState * context,uint8_t handle)455 static inline void *chppClientContextOfHandle(struct ChppAppState *context,
456                                               uint8_t handle) {
457   CHPP_DEBUG_ASSERT(CHPP_SERVICE_INDEX_OF_HANDLE(handle) <
458                     context->registeredClientCount);
459   return context
460       ->registeredClientContexts[context->clientIndexOfServiceIndex
461                                      [CHPP_SERVICE_INDEX_OF_HANDLE(handle)]];
462 }
463 
464 /**
465  * Returns a pointer to the client/service struct of a particular negotiated
466  * client/service handle.
467  * It is up to the caller to ensure the handle number is valid.
468  *
469  * @param appContext Maintains status for each app layer instance.
470  * @param handle Handle number for the service.
471  * @param type Message type (indicates if this is for a client or service).
472  *
473  * @return Pointer to the client/service struct of the service handle.
474  */
chppClientServiceContextOfHandle(struct ChppAppState * appContext,uint8_t handle,enum ChppMessageType type)475 static void *chppClientServiceContextOfHandle(struct ChppAppState *appContext,
476                                               uint8_t handle,
477                                               enum ChppMessageType type) {
478   switch (CHPP_APP_GET_MESSAGE_TYPE(type)) {
479     case CHPP_MESSAGE_TYPE_CLIENT_REQUEST:
480     case CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION: {
481       return chppServiceContextOfHandle(appContext, handle);
482       break;
483     }
484     case CHPP_MESSAGE_TYPE_SERVICE_RESPONSE:
485     case CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION: {
486       return chppClientContextOfHandle(appContext, handle);
487       break;
488     }
489     default: {
490       CHPP_LOGE("Unknown type=0x%" PRIx8 " (H#%" PRIu8 ")", type, handle);
491       return NULL;
492     }
493   }
494 }
495 
496 /**
497  * Processes a received datagram that is determined to be for a predefined CHPP
498  * service. Responds with an error if unsuccessful.
499  *
500  * @param context Maintains status for each app layer instance.
501  * @param buf Input data. Cannot be null.
502  * @param len Length of input data in bytes.
503  */
chppProcessPredefinedHandleDatagram(struct ChppAppState * context,uint8_t * buf,size_t len)504 static void chppProcessPredefinedHandleDatagram(struct ChppAppState *context,
505                                                 uint8_t *buf, size_t len) {
506   struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
507   bool success = true;
508 
509   switch (CHPP_APP_GET_MESSAGE_TYPE(rxHeader->type)) {
510     case CHPP_MESSAGE_TYPE_CLIENT_REQUEST: {
511       success = chppProcessPredefinedClientRequest(context, buf, len);
512       break;
513     }
514     case CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION: {
515       success = chppProcessPredefinedClientNotification(context, buf, len);
516       break;
517     }
518     case CHPP_MESSAGE_TYPE_SERVICE_RESPONSE: {
519       success = chppProcessPredefinedServiceResponse(context, buf, len);
520       break;
521     }
522     case CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION: {
523       success = chppProcessPredefinedServiceNotification(context, buf, len);
524       break;
525     }
526     default: {
527       success = false;
528     }
529   }
530 
531   if (success == false) {
532     CHPP_LOGE("H#%" PRIu8 " undefined msg type=0x%" PRIx8 " (len=%" PRIuSIZE
533               ", ID=%" PRIu8 ")",
534               rxHeader->handle, rxHeader->type, len, rxHeader->transaction);
535     chppEnqueueTxErrorDatagram(context->transportContext,
536                                CHPP_TRANSPORT_ERROR_APPLAYER);
537   }
538 }
539 
540 /**
541  * Processes a received datagram that is determined to be for a negotiated CHPP
542  * client or service. Responds with an error if unsuccessful.
543  *
544  * @param context Maintains status for each app layer instance.
545  * @param buf Input data. Cannot be null.
546  * @param len Length of input data in bytes.
547  */
chppProcessNegotiatedHandleDatagram(struct ChppAppState * context,uint8_t * buf,size_t len)548 static void chppProcessNegotiatedHandleDatagram(struct ChppAppState *context,
549                                                 uint8_t *buf, size_t len) {
550   struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
551   enum ChppMessageType messageType = CHPP_APP_GET_MESSAGE_TYPE(rxHeader->type);
552 
553   void *clientServiceContext =
554       chppClientServiceContextOfHandle(context, rxHeader->handle, messageType);
555   if (clientServiceContext == NULL) {
556     CHPP_LOGE("H#%" PRIu8 " missing ctx (msg=0x%" PRIx8 " len=%" PRIuSIZE
557               ", ID=%" PRIu8 ")",
558               rxHeader->handle, rxHeader->type, len, rxHeader->transaction);
559     chppEnqueueTxErrorDatagram(context->transportContext,
560                                CHPP_TRANSPORT_ERROR_APPLAYER);
561     CHPP_DEBUG_ASSERT(false);
562     return;
563   }
564 
565   ChppDispatchFunction *dispatchFunc =
566       chppGetDispatchFunction(context, rxHeader->handle, messageType);
567   if (dispatchFunc == NULL) {
568     CHPP_LOGE("H#%" PRIu8 " unsupported msg=0x%" PRIx8 " (len=%" PRIuSIZE
569               ", ID=%" PRIu8 ")",
570               rxHeader->handle, rxHeader->type, len, rxHeader->transaction);
571     chppEnqueueTxErrorDatagram(context->transportContext,
572                                CHPP_TRANSPORT_ERROR_APPLAYER);
573     return;
574   }
575 
576   // All good. Dispatch datagram and possibly notify a waiting client
577   enum ChppAppErrorCode error = dispatchFunc(clientServiceContext, buf, len);
578 
579   if (error != CHPP_APP_ERROR_NONE) {
580     CHPP_LOGE("RX dispatch err=0x%" PRIx16 " H#%" PRIu8 " type=0x%" PRIx8
581               " ID=%" PRIu8 " cmd=0x%" PRIx16 " len=%" PRIuSIZE,
582               error, rxHeader->handle, rxHeader->type, rxHeader->transaction,
583               rxHeader->command, len);
584 
585     // Only client requests require a dispatch failure response.
586     if (messageType == CHPP_MESSAGE_TYPE_CLIENT_REQUEST) {
587       struct ChppAppHeader *response =
588           chppAllocServiceResponseFixed(rxHeader, struct ChppAppHeader);
589       if (response == NULL) {
590         CHPP_LOG_OOM();
591       } else {
592         response->error = (uint8_t)error;
593         chppEnqueueTxDatagramOrFail(context->transportContext, response,
594                                     sizeof(*response));
595       }
596     }
597     return;
598   }
599 
600   if (messageType == CHPP_MESSAGE_TYPE_SERVICE_RESPONSE) {
601     // Datagram is a service response. Check for synchronous operation and
602     // notify waiting client if needed.
603 
604     struct ChppClientState *clientState =
605         (struct ChppClientState *)clientServiceContext;
606     chppMutexLock(&clientState->responseMutex);
607     clientState->responseReady = true;
608     CHPP_LOGD(
609         "Finished dispatching a service response. Notifying a potential "
610         "synchronous client");
611     chppConditionVariableSignal(&clientState->responseCondVar);
612     chppMutexUnlock(&clientState->responseMutex);
613   }
614 }
615 
616 /************************************************
617  *  Public Functions
618  ***********************************************/
619 
chppAppInit(struct ChppAppState * appContext,struct ChppTransportState * transportContext)620 void chppAppInit(struct ChppAppState *appContext,
621                  struct ChppTransportState *transportContext) {
622   // Default initialize all service/clients
623   struct ChppClientServiceSet set;
624   memset(&set, 0xff, sizeof(set));  // set all bits to 1
625 
626   chppAppInitWithClientServiceSet(appContext, transportContext, set);
627 }
628 
chppAppInitWithClientServiceSet(struct ChppAppState * appContext,struct ChppTransportState * transportContext,struct ChppClientServiceSet clientServiceSet)629 void chppAppInitWithClientServiceSet(
630     struct ChppAppState *appContext,
631     struct ChppTransportState *transportContext,
632     struct ChppClientServiceSet clientServiceSet) {
633   CHPP_NOT_NULL(appContext);
634 
635   CHPP_LOGD("App Init");
636 
637   memset(appContext, 0, sizeof(*appContext));
638 
639   appContext->clientServiceSet = clientServiceSet;
640   appContext->transportContext = transportContext;
641   appContext->nextRequestTimeoutNs = CHPP_TIME_MAX;
642 
643   chppPalSystemApiInit(appContext);
644 
645 #ifdef CHPP_SERVICE_ENABLED
646   chppRegisterCommonServices(appContext);
647 #endif
648 
649 #ifdef CHPP_CLIENT_ENABLED
650   chppRegisterCommonClients(appContext);
651   chppInitBasicClients(appContext);
652 #endif
653 }
654 
chppAppDeinit(struct ChppAppState * appContext)655 void chppAppDeinit(struct ChppAppState *appContext) {
656   CHPP_LOGD("App deinit");
657 
658 #ifdef CHPP_CLIENT_ENABLED
659   chppDeinitMatchedClients(appContext);
660   chppDeinitBasicClients(appContext);
661   chppDeregisterCommonClients(appContext);
662 #endif
663 
664 #ifdef CHPP_SERVICE_ENABLED
665   chppDeregisterCommonServices(appContext);
666 #endif
667 
668   chppPalSystemApiDeinit(appContext);
669 }
670 
chppAppProcessRxDatagram(struct ChppAppState * context,uint8_t * buf,size_t len)671 void chppAppProcessRxDatagram(struct ChppAppState *context, uint8_t *buf,
672                               size_t len) {
673   struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
674 
675   if (len == 0) {
676     CHPP_DEBUG_ASSERT_LOG(false, "App rx w/ len 0");
677 
678   } else if (len < sizeof(struct ChppAppHeader)) {
679     uint8_t *handle = (uint8_t *)buf;
680     CHPP_LOGD("RX datagram len=%" PRIuSIZE " H#%" PRIu8, len, *handle);
681 
682   } else if (rxHeader->error != CHPP_APP_ERROR_NONE) {
683     CHPP_LOGE("RX datagram len=%" PRIuSIZE " H#%" PRIu8 " type=0x%" PRIx8
684               " ID=%" PRIu8 " ERR=%" PRIu8 " cmd=0x%" PRIx16,
685               len, rxHeader->handle, rxHeader->type, rxHeader->transaction,
686               rxHeader->error, rxHeader->command);
687   } else {
688     CHPP_LOGD("RX datagram len=%" PRIuSIZE " H#%" PRIu8 " type=0x%" PRIx8
689               " ID=%" PRIu8 " err=%" PRIu8 " cmd=0x%" PRIx16,
690               len, rxHeader->handle, rxHeader->type, rxHeader->transaction,
691               rxHeader->error, rxHeader->command);
692   }
693 
694   if (!chppDatagramLenIsOk(context, rxHeader, len)) {
695     chppEnqueueTxErrorDatagram(context->transportContext,
696                                CHPP_TRANSPORT_ERROR_APPLAYER);
697 
698   } else {
699     if (rxHeader->handle == CHPP_HANDLE_NONE) {
700       chppDispatchNonHandle(context, buf, len);
701 
702     } else if (rxHeader->handle < CHPP_HANDLE_NEGOTIATED_RANGE_START) {
703       chppProcessPredefinedHandleDatagram(context, buf, len);
704 
705     } else {
706       chppProcessNegotiatedHandleDatagram(context, buf, len);
707     }
708   }
709 
710   chppDatagramProcessDoneCb(context->transportContext, buf);
711 }
712 
chppAppProcessReset(struct ChppAppState * context)713 void chppAppProcessReset(struct ChppAppState *context) {
714 #ifdef CHPP_CLIENT_ENABLED_DISCOVERY
715   if (!context->isDiscoveryComplete) {
716     chppInitiateDiscovery(context);
717 
718   } else {
719     // Notify matched clients that a reset happened
720     for (uint8_t i = 0; i < context->discoveredServiceCount; i++) {
721       uint8_t clientIndex = context->clientIndexOfServiceIndex[i];
722       if (clientIndex != CHPP_CLIENT_INDEX_NONE) {
723         // Discovered service has a matched client
724         ChppNotifierFunction *ResetNotifierFunction =
725             chppGetClientResetNotifierFunction(context, clientIndex);
726 
727         CHPP_LOGD("Client #%" PRIu8 " (H#%d) reset notifier found=%d",
728                   clientIndex, CHPP_SERVICE_HANDLE_OF_INDEX(i),
729                   (ResetNotifierFunction != NULL));
730 
731         if (ResetNotifierFunction != NULL) {
732           ResetNotifierFunction(context->registeredClientContexts[clientIndex]);
733         }
734       }
735     }
736   }
737 #endif  // CHPP_CLIENT_ENABLED_DISCOVERY
738 
739   // Notify registered services that a reset happened
740   for (uint8_t i = 0; i < context->registeredServiceCount; i++) {
741     ChppNotifierFunction *ResetNotifierFunction =
742         chppGetServiceResetNotifierFunction(context, i);
743 
744     CHPP_LOGD("Service #%" PRIu8 " (H#%d) reset notifier found=%d", i,
745               CHPP_SERVICE_HANDLE_OF_INDEX(i), (ResetNotifierFunction != NULL));
746 
747     if (ResetNotifierFunction != NULL) {
748       ResetNotifierFunction(context->registeredServiceContexts[i]);
749     }
750   }
751 
752 #ifdef CHPP_CLIENT_ENABLED_TIMESYNC
753   // Reinitialize time offset
754   chppTimesyncClientReset(context);
755 #endif
756 }
757 
chppUuidToStr(const uint8_t uuid[CHPP_SERVICE_UUID_LEN],char strOut[CHPP_SERVICE_UUID_STRING_LEN])758 void chppUuidToStr(const uint8_t uuid[CHPP_SERVICE_UUID_LEN],
759                    char strOut[CHPP_SERVICE_UUID_STRING_LEN]) {
760   snprintf(
761       strOut, CHPP_SERVICE_UUID_STRING_LEN,
762       "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
763       uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
764       uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],
765       uuid[15]);
766 }
767 
chppAppErrorToChreError(uint8_t chppError)768 uint8_t chppAppErrorToChreError(uint8_t chppError) {
769   switch (chppError) {
770     case CHPP_APP_ERROR_NONE:
771     case CHPP_APP_ERROR_INVALID_ARG:
772     case CHPP_APP_ERROR_BUSY:
773     case CHPP_APP_ERROR_OOM:
774     case CHPP_APP_ERROR_UNSUPPORTED:
775     case CHPP_APP_ERROR_TIMEOUT:
776     case CHPP_APP_ERROR_DISABLED:
777     case CHPP_APP_ERROR_RATELIMITED: {
778       // CHRE and CHPP error values are identical in these cases
779       return chppError;
780     }
781     default: {
782       return CHRE_ERROR;
783     }
784   }
785 }
786 
chppAppShortResponseErrorHandler(uint8_t * buf,size_t len,const char * responseName)787 uint8_t chppAppShortResponseErrorHandler(uint8_t *buf, size_t len,
788                                          const char *responseName) {
789   CHPP_ASSERT(len >= sizeof(struct ChppAppHeader));
790   struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
791 
792   if (rxHeader->error == CHPP_APP_ERROR_NONE) {
793     CHPP_LOGE("%s resp short len=%" PRIuSIZE, responseName, len);
794     return CHRE_ERROR;
795   }
796 
797   CHPP_LOGD("%s resp short len=%" PRIuSIZE, responseName, len);
798   return chppAppErrorToChreError(rxHeader->error);
799 }
800