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