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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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 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 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 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 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 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