• 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         // len remains SIZE_MAX
272         CHPP_LOGE("Invalid H#%" PRIu8, handle);
273     }
274 
275   } else {  // Negotiated
276     enum ChppMessageType messageType =
277         CHPP_APP_GET_MESSAGE_TYPE(rxHeader->type);
278 
279     switch (messageType) {
280       case CHPP_MESSAGE_TYPE_CLIENT_REQUEST:
281       case CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION: {
282         const struct ChppService *service =
283             chppServiceOfHandle(context, handle);
284         if (service != NULL) {
285           minLen = service->minLength;
286         }
287         break;
288       }
289       case CHPP_MESSAGE_TYPE_SERVICE_RESPONSE:
290       case CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION: {
291         const struct ChppClient *client = chppClientOfHandle(context, handle);
292         if (client != NULL) {
293           minLen = client->minLength;
294         }
295         break;
296       }
297       default: {
298         break;
299       }
300     }
301 
302     if (minLen == SIZE_MAX) {
303       CHPP_LOGE("Invalid type=%d or H#%" PRIu8, messageType, handle);
304     }
305   }
306 
307   if ((len < minLen) && (minLen != SIZE_MAX)) {
308     CHPP_LOGE("Datagram len=%" PRIuSIZE " < %" PRIuSIZE " for H#%" PRIu8, len,
309               minLen, handle);
310   }
311   return (len >= minLen) && (minLen != SIZE_MAX);
312 }
313 
314 /**
315  * Returns the dispatch function of a particular negotiated client/service
316  * handle and message type. This shall be null if it is unsupported by the
317  * service.
318  *
319  * @param context Maintains status for each app layer instance.
320  * @param handle Handle number for the client/service.
321  * @param type Message type.
322  *
323  * @return Pointer to a function that dispatches incoming datagrams for any
324  * particular client/service.
325  */
chppGetDispatchFunction(struct ChppAppState * context,uint8_t handle,enum ChppMessageType type)326 ChppDispatchFunction *chppGetDispatchFunction(struct ChppAppState *context,
327                                               uint8_t handle,
328                                               enum ChppMessageType type) {
329   // chppDatagramLenIsOk() has already confirmed that the handle # is valid.
330   // Therefore, no additional checks are necessary for chppClientOfHandle(),
331   // chppServiceOfHandle(), or chppClientServiceContextOfHandle().
332 
333   switch (CHPP_APP_GET_MESSAGE_TYPE(type)) {
334     case CHPP_MESSAGE_TYPE_CLIENT_REQUEST: {
335       return chppServiceOfHandle(context, handle)->requestDispatchFunctionPtr;
336       break;
337     }
338     case CHPP_MESSAGE_TYPE_SERVICE_RESPONSE: {
339       struct ChppClientState *clientState =
340           (struct ChppClientState *)chppClientServiceContextOfHandle(
341               context, handle, type);
342       if (clientState->openState == CHPP_OPEN_STATE_CLOSED) {
343         CHPP_LOGE("RX service response but client closed");
344       } else {
345         return chppClientOfHandle(context, handle)->responseDispatchFunctionPtr;
346       }
347       break;
348     }
349     case CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION: {
350       return chppServiceOfHandle(context, handle)
351           ->notificationDispatchFunctionPtr;
352       break;
353     }
354     case CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION: {
355       struct ChppClientState *clientState =
356           (struct ChppClientState *)chppClientServiceContextOfHandle(
357               context, handle, type);
358       if (clientState->openState == CHPP_OPEN_STATE_CLOSED) {
359         CHPP_LOGE("RX service notification but client closed");
360       } else {
361         return chppClientOfHandle(context, handle)
362             ->notificationDispatchFunctionPtr;
363       }
364       break;
365     }
366   }
367 
368   return NULL;
369 }
370 
371 /**
372  * Returns the reset notification function pointer of a particular negotiated
373  * client. The function pointer will be set to null by clients that do not need
374  * or support a reset notification.
375  *
376  * @param context Maintains status for each app layer instance.
377  * @param index Index of the registered client.
378  *
379  * @return Pointer to the reset notification function.
380  */
chppGetClientResetNotifierFunction(struct ChppAppState * context,uint8_t index)381 ChppNotifierFunction *chppGetClientResetNotifierFunction(
382     struct ChppAppState *context, uint8_t index) {
383   return context->registeredClients[index]->resetNotifierFunctionPtr;
384 }
385 
386 /**
387  * Returns the reset function pointer of a particular registered service. The
388  * function pointer will be set to null by services that do not need or support
389  * a reset notification.
390  *
391  * @param context Maintains status for each app layer instance.
392  * @param index Index of the registered service.
393  *
394  * @return Pointer to the reset function.
395  */
chppGetServiceResetNotifierFunction(struct ChppAppState * context,uint8_t index)396 ChppNotifierFunction *chppGetServiceResetNotifierFunction(
397     struct ChppAppState *context, uint8_t index) {
398   return context->registeredServices[index]->resetNotifierFunctionPtr;
399 }
400 
401 /**
402  * Returns a pointer to the ChppService struct of the service matched to a
403  * negotiated handle. Returns null if a service doesn't exist for the handle.
404  *
405  * @param context Maintains status for each app layer instance.
406  * @param handle Handle number.
407  *
408  * @return Pointer to the ChppService struct of a particular service handle.
409  */
chppServiceOfHandle(struct ChppAppState * context,uint8_t handle)410 static inline const struct ChppService *chppServiceOfHandle(
411     struct ChppAppState *context, uint8_t handle) {
412   uint8_t serviceIndex = CHPP_SERVICE_INDEX_OF_HANDLE(handle);
413   if (serviceIndex < context->registeredServiceCount) {
414     return context->registeredServices[serviceIndex];
415   }
416 
417   return NULL;
418 }
419 
420 /**
421  * Returns a pointer to the ChppClient struct of the client matched to a
422  * negotiated handle. Returns null if a client doesn't exist for the handle.
423  *
424  * @param context Maintains status for each app layer instance.
425  * @param handle Handle number.
426  *
427  * @return Pointer to the ChppClient struct matched to a particular handle.
428  */
chppClientOfHandle(struct ChppAppState * context,uint8_t handle)429 static inline const struct ChppClient *chppClientOfHandle(
430     struct ChppAppState *context, uint8_t handle) {
431   uint8_t serviceIndex = CHPP_SERVICE_INDEX_OF_HANDLE(handle);
432   if (serviceIndex < context->discoveredServiceCount) {
433     uint8_t clientIndex = context->clientIndexOfServiceIndex[serviceIndex];
434     if (clientIndex < context->registeredClientCount) {
435       return context->registeredClients[clientIndex];
436     }
437   }
438 
439   return NULL;
440 }
441 
442 /**
443  * Returns a pointer to the service struct of a particular negotiated service
444  * handle.
445  * It is up to the caller to ensure the handle number is valid.
446  *
447  * @param context Maintains status for each app layer instance.
448  * @param handle Handle number for the service.
449  *
450  * @return Pointer to the context struct of the service.
451  */
chppServiceContextOfHandle(struct ChppAppState * context,uint8_t handle)452 static inline void *chppServiceContextOfHandle(struct ChppAppState *context,
453                                                uint8_t handle) {
454   CHPP_DEBUG_ASSERT(CHPP_SERVICE_INDEX_OF_HANDLE(handle) <
455                     context->registeredServiceCount);
456   return context
457       ->registeredServiceContexts[CHPP_SERVICE_INDEX_OF_HANDLE(handle)];
458 }
459 
460 /**
461  * Returns a pointer to the client struct of a particular negotiated client
462  * handle.
463  * It is up to the caller to ensure the handle number is valid.
464  *
465  * @param context Maintains status for each app layer instance.
466  * @param handle Handle number for the service.
467  *
468  * @return Pointer to the ChppService struct of the client.
469  */
chppClientContextOfHandle(struct ChppAppState * context,uint8_t handle)470 static inline void *chppClientContextOfHandle(struct ChppAppState *context,
471                                               uint8_t handle) {
472   CHPP_DEBUG_ASSERT(CHPP_SERVICE_INDEX_OF_HANDLE(handle) <
473                     context->registeredClientCount);
474   return context
475       ->registeredClientContexts[context->clientIndexOfServiceIndex
476                                      [CHPP_SERVICE_INDEX_OF_HANDLE(handle)]];
477 }
478 
479 /**
480  * Returns a pointer to the client/service struct of a particular negotiated
481  * client/service handle.
482  * It is up to the caller to ensure the handle number is valid.
483  *
484  * @param appContext Maintains status for each app layer instance.
485  * @param handle Handle number for the service.
486  * @param type Message type (indicates if this is for a client or service).
487  *
488  * @return Pointer to the client/service struct of the service handle.
489  */
chppClientServiceContextOfHandle(struct ChppAppState * appContext,uint8_t handle,enum ChppMessageType type)490 static void *chppClientServiceContextOfHandle(struct ChppAppState *appContext,
491                                               uint8_t handle,
492                                               enum ChppMessageType type) {
493   switch (CHPP_APP_GET_MESSAGE_TYPE(type)) {
494     case CHPP_MESSAGE_TYPE_CLIENT_REQUEST:
495     case CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION: {
496       return chppServiceContextOfHandle(appContext, handle);
497       break;
498     }
499     case CHPP_MESSAGE_TYPE_SERVICE_RESPONSE:
500     case CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION: {
501       return chppClientContextOfHandle(appContext, handle);
502       break;
503     }
504     default: {
505       CHPP_LOGE("Unknown type=0x%" PRIx8 " (H#%" PRIu8 ")", type, handle);
506       return NULL;
507     }
508   }
509 }
510 
511 /**
512  * Processes a received datagram that is determined to be for a predefined CHPP
513  * service. Responds with an error if unsuccessful.
514  *
515  * @param context Maintains status for each app layer instance.
516  * @param buf Input data. Cannot be null.
517  * @param len Length of input data in bytes.
518  */
chppProcessPredefinedHandleDatagram(struct ChppAppState * context,uint8_t * buf,size_t len)519 static void chppProcessPredefinedHandleDatagram(struct ChppAppState *context,
520                                                 uint8_t *buf, size_t len) {
521   struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
522   bool success = true;
523 
524   switch (CHPP_APP_GET_MESSAGE_TYPE(rxHeader->type)) {
525     case CHPP_MESSAGE_TYPE_CLIENT_REQUEST: {
526       success = chppProcessPredefinedClientRequest(context, buf, len);
527       break;
528     }
529     case CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION: {
530       success = chppProcessPredefinedClientNotification(context, buf, len);
531       break;
532     }
533     case CHPP_MESSAGE_TYPE_SERVICE_RESPONSE: {
534       success = chppProcessPredefinedServiceResponse(context, buf, len);
535       break;
536     }
537     case CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION: {
538       success = chppProcessPredefinedServiceNotification(context, buf, len);
539       break;
540     }
541     default: {
542       success = false;
543     }
544   }
545 
546   if (success == false) {
547     CHPP_LOGE("H#%" PRIu8 " undefined msg type=0x%" PRIx8 " (len=%" PRIuSIZE
548               ", ID=%" PRIu8 ")",
549               rxHeader->handle, rxHeader->type, len, rxHeader->transaction);
550     chppEnqueueTxErrorDatagram(context->transportContext,
551                                CHPP_TRANSPORT_ERROR_APPLAYER);
552   }
553 }
554 
555 /**
556  * Processes a received datagram that is determined to be for a negotiated CHPP
557  * client or service. Responds with an error if unsuccessful.
558  *
559  * @param context Maintains status for each app layer instance.
560  * @param buf Input data. Cannot be null.
561  * @param len Length of input data in bytes.
562  */
chppProcessNegotiatedHandleDatagram(struct ChppAppState * context,uint8_t * buf,size_t len)563 static void chppProcessNegotiatedHandleDatagram(struct ChppAppState *context,
564                                                 uint8_t *buf, size_t len) {
565   struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
566   enum ChppMessageType messageType = CHPP_APP_GET_MESSAGE_TYPE(rxHeader->type);
567 
568   void *clientServiceContext =
569       chppClientServiceContextOfHandle(context, rxHeader->handle, messageType);
570   if (clientServiceContext == NULL) {
571     CHPP_LOGE("H#%" PRIu8 " missing ctx (msg=0x%" PRIx8 " len=%" PRIuSIZE
572               ", ID=%" PRIu8 ")",
573               rxHeader->handle, rxHeader->type, len, rxHeader->transaction);
574     chppEnqueueTxErrorDatagram(context->transportContext,
575                                CHPP_TRANSPORT_ERROR_APPLAYER);
576     CHPP_DEBUG_ASSERT(false);
577 
578   } else {
579     ChppDispatchFunction *dispatchFunc =
580         chppGetDispatchFunction(context, rxHeader->handle, messageType);
581     if (dispatchFunc == NULL) {
582       CHPP_LOGE("H#%" PRIu8 " unsupported msg=0x%" PRIx8 " (len=%" PRIuSIZE
583                 ", ID=%" PRIu8 ")",
584                 rxHeader->handle, rxHeader->type, len, rxHeader->transaction);
585       chppEnqueueTxErrorDatagram(context->transportContext,
586                                  CHPP_TRANSPORT_ERROR_APPLAYER);
587 
588     } else {
589       // All good. Dispatch datagram and possibly notify a waiting client
590 
591       enum ChppAppErrorCode error =
592           dispatchFunc(clientServiceContext, buf, len);
593       if (error != CHPP_APP_ERROR_NONE) {
594         CHPP_LOGE("RX dispatch err=0x%" PRIx16 " H#%" PRIu8 " type=0x%" PRIx8
595                   " ID=%" PRIu8 " cmd=0x%" PRIx16 " len=%" PRIuSIZE,
596                   error, rxHeader->handle, rxHeader->type,
597                   rxHeader->transaction, rxHeader->command, len);
598 
599         // Only client requests require a dispatch failure response.
600         if (messageType == CHPP_MESSAGE_TYPE_CLIENT_REQUEST) {
601           struct ChppAppHeader *response =
602               chppAllocServiceResponseFixed(rxHeader, struct ChppAppHeader);
603           if (response == NULL) {
604             CHPP_LOG_OOM();
605           } else {
606             response->error = (uint8_t)error;
607             chppEnqueueTxDatagramOrFail(context->transportContext, response,
608                                         sizeof(*response));
609           }
610         }
611       } else if (messageType == CHPP_MESSAGE_TYPE_SERVICE_RESPONSE) {
612         // Datagram is a service response. Check for synchronous operation and
613         // notify waiting client if needed.
614 
615         struct ChppClientState *clientState =
616             (struct ChppClientState *)clientServiceContext;
617         chppMutexLock(&clientState->responseMutex);
618         clientState->responseReady = true;
619         CHPP_LOGD(
620             "Finished dispatching a service response. Notifying a potential "
621             "synchronous client");
622         chppConditionVariableSignal(&clientState->responseCondVar);
623         chppMutexUnlock(&clientState->responseMutex);
624       }
625     }
626   }
627 }
628 
629 /************************************************
630  *  Public Functions
631  ***********************************************/
632 
chppAppInit(struct ChppAppState * appContext,struct ChppTransportState * transportContext)633 void chppAppInit(struct ChppAppState *appContext,
634                  struct ChppTransportState *transportContext) {
635   // Default initialize all service/clients
636   struct ChppClientServiceSet set;
637   memset(&set, 0xff, sizeof(set));  // set all bits to 1
638 
639   chppAppInitWithClientServiceSet(appContext, transportContext, set);
640 }
641 
chppAppInitWithClientServiceSet(struct ChppAppState * appContext,struct ChppTransportState * transportContext,struct ChppClientServiceSet clientServiceSet)642 void chppAppInitWithClientServiceSet(
643     struct ChppAppState *appContext,
644     struct ChppTransportState *transportContext,
645     struct ChppClientServiceSet clientServiceSet) {
646   CHPP_NOT_NULL(appContext);
647 
648   CHPP_LOGD("App Init");
649 
650   memset(appContext, 0, sizeof(*appContext));
651 
652   appContext->clientServiceSet = clientServiceSet;
653   appContext->transportContext = transportContext;
654   appContext->nextRequestTimeoutNs = CHPP_TIME_MAX;
655 
656   chppPalSystemApiInit(appContext);
657 
658 #ifdef CHPP_SERVICE_ENABLED
659   chppRegisterCommonServices(appContext);
660 #endif
661 
662 #ifdef CHPP_CLIENT_ENABLED
663   chppRegisterCommonClients(appContext);
664   chppInitBasicClients(appContext);
665 #endif
666 }
667 
chppAppDeinit(struct ChppAppState * appContext)668 void chppAppDeinit(struct ChppAppState *appContext) {
669   CHPP_LOGD("App deinit");
670 
671 #ifdef CHPP_CLIENT_ENABLED
672   chppDeinitMatchedClients(appContext);
673   chppDeinitBasicClients(appContext);
674   chppDeregisterCommonClients(appContext);
675 #endif
676 
677 #ifdef CHPP_SERVICE_ENABLED
678   chppDeregisterCommonServices(appContext);
679 #endif
680 
681   chppPalSystemApiDeinit(appContext);
682 }
683 
chppAppProcessRxDatagram(struct ChppAppState * context,uint8_t * buf,size_t len)684 void chppAppProcessRxDatagram(struct ChppAppState *context, uint8_t *buf,
685                               size_t len) {
686   struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
687 
688   if (len == 0) {
689     CHPP_DEBUG_ASSERT_LOG(false, "App rx w/ len 0");
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 
chppAppShortResponseErrorHandler(uint8_t * buf,size_t len,const char * responseName)800 uint8_t chppAppShortResponseErrorHandler(uint8_t *buf, size_t len,
801                                          const char *responseName) {
802   CHPP_ASSERT(len >= sizeof(struct ChppAppHeader));
803   uint8_t result = CHRE_ERROR;
804   struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
805 
806   if (rxHeader->error == CHPP_APP_ERROR_NONE) {
807     CHPP_LOGE("%s resp short len=%" PRIuSIZE, responseName, len);
808   } else {
809     CHPP_LOGI("%s resp short len=%" PRIuSIZE, responseName, len);
810     result = chppAppErrorToChreError(rxHeader->error);
811   }
812 
813   return result;
814 }
815