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 #ifndef CHPP_APP_H_ 18 #define CHPP_APP_H_ 19 20 #include <stdbool.h> 21 #include <stddef.h> 22 #include <stdint.h> 23 24 #include "chpp/condition_variable.h" 25 #include "chpp/macros.h" 26 #include "chpp/transport.h" 27 28 #ifdef __cplusplus 29 extern "C" { 30 #endif 31 32 /************************************************ 33 * Public Definitions 34 ***********************************************/ 35 36 /** 37 * Maximum number of services that can be registered by CHPP (not including 38 * predefined services), if not defined by the build system. 39 */ 40 #ifndef CHPP_MAX_REGISTERED_SERVICES 41 #define CHPP_MAX_REGISTERED_SERVICES 1 42 #endif 43 44 /** 45 * Maximum number of clients that can be registered by CHPP (not including 46 * predefined clients), if not defined by the build system. 47 */ 48 #ifndef CHPP_MAX_REGISTERED_CLIENTS 49 #define CHPP_MAX_REGISTERED_CLIENTS 1 50 #endif 51 52 /** 53 * Maximum number of services that can be discovered by CHPP (not including 54 * predefined services), if not defined by the build system. 55 */ 56 #ifndef CHPP_MAX_DISCOVERED_SERVICES 57 #define CHPP_MAX_DISCOVERED_SERVICES \ 58 MAX(CHPP_MAX_REGISTERED_SERVICES, CHPP_MAX_REGISTERED_CLIENTS) 59 #endif 60 61 /** 62 * Default value for reserved fields. 63 */ 64 #define CHPP_RESERVED 0 65 66 /** 67 * Client index number when there is no matching client 68 */ 69 #define CHPP_CLIENT_INDEX_NONE 0xff 70 71 /** 72 * App layer command at initialization. 73 */ 74 #define CHPP_APP_COMMAND_NONE 0 75 76 /** 77 * Handle Numbers in ChppAppHeader 78 */ 79 enum ChppHandleNumber { 80 //! Handleless communication 81 CHPP_HANDLE_NONE = 0x00, 82 83 //! Loopback Service 84 CHPP_HANDLE_LOOPBACK = 0x01, 85 86 //! Time Service 87 CHPP_HANDLE_TIMESYNC = 0x02, 88 89 //! Discovery Service 90 CHPP_HANDLE_DISCOVERY = 0x0F, 91 92 //! Negotiated Services (starting from this offset) 93 CHPP_HANDLE_NEGOTIATED_RANGE_START = 0x10, 94 }; 95 96 /** 97 * Message Types as used in ChppAppHeader 98 */ 99 #define CHPP_APP_MASK_MESSAGE_TYPE LEAST_SIGNIFICANT_NIBBLE 100 #define CHPP_APP_GET_MESSAGE_TYPE(value) \ 101 ((enum ChppMessageType)( \ 102 (value)&CHPP_APP_MASK_MESSAGE_TYPE)) // TODO: Consider checking if this 103 // maps into a valid enum 104 enum ChppMessageType { 105 //! Request from client. Needs response from service. 106 CHPP_MESSAGE_TYPE_CLIENT_REQUEST = 0, 107 108 //! Response from service (with the same Command and Transaction ID as the 109 //! client request). 110 CHPP_MESSAGE_TYPE_SERVICE_RESPONSE = 1, 111 112 //! Notification from client. Service shall not respond. 113 CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION = 2, 114 115 //! Notification from service. Client shall not respond. 116 CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION = 3, 117 }; 118 119 /** 120 * Error codes used by the app layer / clients / services. 121 */ 122 enum ChppAppErrorCode { 123 //! Success (no error) 124 CHPP_APP_ERROR_NONE = 0, 125 //! Invalid command 126 CHPP_APP_ERROR_INVALID_COMMAND = 1, 127 //! Invalid argument(s) 128 CHPP_APP_ERROR_INVALID_ARG = 2, 129 //! Busy 130 CHPP_APP_ERROR_BUSY = 3, 131 //! Out of memory 132 CHPP_APP_ERROR_OOM = 4, 133 //! Feature not supported 134 CHPP_APP_ERROR_UNSUPPORTED = 5, 135 //! Timeout 136 CHPP_APP_ERROR_TIMEOUT = 6, 137 //! Functionality disabled (e.g. per user configuration) 138 CHPP_APP_ERROR_DISABLED = 7, 139 //! Rate limit exceeded (try again later) 140 CHPP_APP_ERROR_RATELIMITED = 8, 141 //! Function in use / blocked by another entity (e.g. the AP) 142 CHPP_APP_ERROR_BLOCKED = 9, 143 //! Invalid length 144 CHPP_APP_ERROR_INVALID_LENGTH = 10, 145 //! CHPP Not Ready 146 CHPP_APP_ERROR_NOT_READY = 11, 147 //! Error outside of CHPP (e.g. PAL API) 148 CHPP_APP_ERROR_BEYOND_CHPP = 12, 149 //! Response not matching a pending request 150 CHPP_APP_ERROR_UNEXPECTED_RESPONSE = 13, 151 //! Conversion failed 152 CHPP_APP_ERROR_CONVERSION_FAILED = 14, 153 //! Unspecified failure 154 CHPP_APP_ERROR_UNSPECIFIED = 255 155 }; 156 157 /** 158 * Open status for clients / services. 159 */ 160 enum ChppOpenState { 161 CHPP_OPEN_STATE_CLOSED = 0, // Closed 162 CHPP_OPEN_STATE_OPENING = 1, // Enables the open request to pass 163 CHPP_OPEN_STATE_WAITING_TO_OPEN = 2, // Waiting for open response 164 CHPP_OPEN_STATE_OPENED = 3, // Opened 165 }; 166 167 /** 168 * CHPP Application Layer header 169 */ 170 CHPP_PACKED_START 171 struct ChppAppHeader { 172 //! Service Handle 173 uint8_t handle; 174 175 //! Most significant nibble (MSN): Reserved 176 //! Least significant nibble (LSN): Message Type from enum ChppMessageType 177 uint8_t type; 178 179 //! Transaction ID 180 uint8_t transaction; 181 182 //! Error if any, from enum ChppAppErrorCode 183 uint8_t error; 184 185 //! Command 186 uint16_t command; 187 188 } CHPP_PACKED_ATTR; 189 CHPP_PACKED_END 190 191 //! Minimum length of a header that includes upto the transaction ID 192 #define CHPP_APP_MIN_LEN_HEADER_WITH_TRANSACTION (3 * sizeof(uint8_t)) 193 194 /** 195 * Function type that dispatches incoming datagrams for any client or service 196 */ 197 typedef enum ChppAppErrorCode(ChppDispatchFunction)(void *context, uint8_t *buf, 198 size_t len); 199 200 /** 201 * Function type that initializes a client and assigns it its handle number 202 */ 203 typedef bool(ChppClientInitFunction)(void *context, uint8_t handle, 204 struct ChppVersion serviceVersion); 205 206 /** 207 * Function type that deinitializes a client. 208 */ 209 typedef void(ChppClientDeinitFunction)(void *context); 210 211 /** 212 * Function type that dispatches a reset notification to any client or service 213 */ 214 typedef void(ChppNotifierFunction)(void *context); 215 216 /** 217 * Length of a service UUID and its human-readable printed form in bytes 218 */ 219 #define CHPP_SERVICE_UUID_LEN 16 220 #define CHPP_SERVICE_UUID_STRING_LEN (16 * 2 + 4 + 1) 221 222 /** 223 * Length of a version number, in bytes (major + minor + revision), per CHPP 224 * spec. 225 */ 226 #define CHPP_SERVICE_VERSION_LEN (1 + 1 + 2) 227 228 /** 229 * Maximum length of a human-readable service name, per CHPP spec. 230 * (15 ASCII characters + null) 231 */ 232 #define CHPP_SERVICE_NAME_MAX_LEN (15 + 1) 233 234 /** 235 * CHPP definition of a service descriptor as sent over the wire. 236 */ 237 CHPP_PACKED_START 238 struct ChppServiceDescriptor { 239 //! UUID of the service. 240 //! Must be generated according to RFC 4122, UUID version 4 (random). 241 uint8_t uuid[CHPP_SERVICE_UUID_LEN]; 242 243 //! Human-readable name of the service for debugging. 244 char name[CHPP_SERVICE_NAME_MAX_LEN]; 245 246 //! Version of the service. 247 struct ChppVersion version; 248 } CHPP_PACKED_ATTR; 249 CHPP_PACKED_END 250 251 /** 252 * CHPP definition of a service as supported on a server. 253 */ 254 struct ChppService { 255 //! Service Descriptor as sent over the wire. 256 struct ChppServiceDescriptor descriptor; 257 258 //! Pointer to the function that is used to notify the service if CHPP is 259 //! reset. 260 ChppNotifierFunction *resetNotifierFunctionPtr; 261 262 //! Pointer to the function that dispatches incoming client requests for the 263 //! service. 264 ChppDispatchFunction *requestDispatchFunctionPtr; 265 266 //! Pointer to the function that dispatches incoming client notifications for 267 //! the service. 268 ChppDispatchFunction *notificationDispatchFunctionPtr; 269 270 //! Minimum valid length of datagrams for the service. 271 size_t minLength; 272 }; 273 274 /** 275 * CHPP definition of a client descriptor. 276 */ 277 struct ChppClientDescriptor { 278 //! UUID of the client. 279 //! Must be generated according to RFC 4122, UUID version 4 (random). 280 uint8_t uuid[CHPP_SERVICE_UUID_LEN]; 281 282 //! Version of the client. 283 struct ChppVersion version; 284 }; 285 286 /** 287 * CHPP definition of a client. 288 */ 289 struct ChppClient { 290 //! Client descriptor. 291 struct ChppClientDescriptor descriptor; 292 293 //! Pointer to the function that is used to notify the client if CHPP is 294 //! reset. 295 ChppNotifierFunction *resetNotifierFunctionPtr; 296 297 //! Pointer to the function that is used to notify the client if CHPP is 298 //! matched to a service. 299 ChppNotifierFunction *matchNotifierFunctionPtr; 300 301 //! Pointer to the function that dispatches incoming service responses for the 302 //! client. 303 //! Service responses are only dispatched to clients that have been opened or 304 //! are in the process of being (re)opened. @see ChppOpenState 305 ChppDispatchFunction *responseDispatchFunctionPtr; 306 307 //! Pointer to the function that dispatches incoming service notifications for 308 //! the client. 309 //! Service notifications are only dispatched to clients that have been 310 //! opened. @see ChppOpenState 311 ChppDispatchFunction *notificationDispatchFunctionPtr; 312 313 //! Pointer to the function that initializes the client (after it is matched 314 //! with a service at discovery) and assigns it its handle number. 315 ChppClientInitFunction *initFunctionPtr; 316 317 //! Pointer to the function that deinitializes the client. 318 ChppClientDeinitFunction *deinitFunctionPtr; 319 320 //! Number of request-response states in the rRStates array. This is a 321 //! uint16_t to match the uint16_t command in struct ChppAppHeader. 322 uint16_t rRStateCount; 323 324 //! Minimum valid length of datagrams for the service. 325 size_t minLength; 326 }; 327 328 /** 329 * Request status for clients. 330 */ 331 enum ChppRequestState { 332 CHPP_REQUEST_STATE_NONE = 0, // No request sent ever 333 CHPP_REQUEST_STATE_REQUEST_SENT = 1, // Sent but no response yet 334 CHPP_REQUEST_STATE_RESPONSE_RCV = 2, // Sent and response received 335 CHPP_REQUEST_STATE_RESPONSE_TIMEOUT = 3, // Timeout. Responded as need be 336 }; 337 338 /** 339 * Maintains the basic state for each request/response functionality of a 340 * client or service. 341 * Any number of these may be included in the (context) status variable of a 342 * client or service (one per every every request/response functionality). 343 */ 344 struct ChppRequestResponseState { 345 uint64_t requestTimeNs; // Time of the last request 346 uint64_t 347 responseTimeNs; // If requestState is CHPP_REQUEST_STATE_REQUEST_SENT, 348 // indicates the timeout time for the request 349 // If requestState is CHPP_REQUEST_STATE_RESPONSE_RCV, 350 // indicates when the response was received 351 352 uint8_t requestState; // From enum ChppRequestState 353 uint8_t transaction; // Transaction ID for the last request/response 354 }; 355 356 /** 357 * Enabled clients and services. 358 */ 359 struct ChppClientServiceSet { 360 bool wifiService : 1; 361 bool gnssService : 1; 362 bool wwanService : 1; 363 bool wifiClient : 1; 364 bool gnssClient : 1; 365 bool wwanClient : 1; 366 bool loopbackClient : 1; 367 }; 368 369 struct ChppLoopbackClientState; 370 struct ChppTimesyncClientState; 371 372 struct ChppAppState { 373 struct ChppTransportState *transportContext; // Pointing to transport context 374 375 const struct chrePalSystemApi *systemApi; // Pointing to the PAL system APIs 376 377 uint8_t registeredServiceCount; // Number of services currently registered 378 379 const struct ChppService *registeredServices[CHPP_MAX_REGISTERED_SERVICES]; 380 381 void *registeredServiceContexts[CHPP_MAX_REGISTERED_SERVICES]; 382 383 uint8_t registeredClientCount; // Number of clients currently registered 384 385 const struct ChppClient *registeredClients[CHPP_MAX_REGISTERED_CLIENTS]; 386 387 const struct ChppClientState 388 *registeredClientStates[CHPP_MAX_REGISTERED_CLIENTS]; 389 390 void *registeredClientContexts[CHPP_MAX_REGISTERED_CLIENTS]; 391 392 uint64_t nextRequestTimeoutNs; 393 394 uint8_t 395 clientIndexOfServiceIndex[CHPP_MAX_DISCOVERED_SERVICES]; // Lookup table 396 397 struct ChppClientServiceSet clientServiceSet; // Enabled client/services 398 399 // Pointers to the contexts of basic clients, which are allocated if and when 400 // they are initialized 401 struct ChppLoopbackClientState *loopbackClientContext; 402 struct ChppTimesyncClientState *timesyncClientContext; 403 404 // For discovery clients 405 bool isDiscoveryClientEverInitialized; 406 bool isDiscoveryClientInitialized; 407 bool isDiscoveryComplete; 408 409 // The number of clients that matched a service during discovery. 410 uint8_t matchedClientCount; 411 412 // The number of services that were found during discovery. 413 uint8_t discoveredServiceCount; 414 415 struct ChppMutex discoveryMutex; 416 struct ChppConditionVariable discoveryCv; 417 }; 418 419 #define CHPP_SERVICE_INDEX_OF_HANDLE(handle) \ 420 ((handle)-CHPP_HANDLE_NEGOTIATED_RANGE_START) 421 422 #define CHPP_SERVICE_HANDLE_OF_INDEX(index) \ 423 ((index) + CHPP_HANDLE_NEGOTIATED_RANGE_START) 424 425 /************************************************ 426 * Public functions 427 ***********************************************/ 428 429 /** 430 * Initializes the CHPP app layer state stored in the parameter appContext. 431 * It is necessary to initialize state for each app layer instance on 432 * every platform. 433 * 434 * @param appContext Maintains status for each app layer instance. 435 * @param transportContext The transport layer status struct associated with 436 * this app layer instance. 437 */ 438 void chppAppInit(struct ChppAppState *appContext, 439 struct ChppTransportState *transportContext); 440 441 /** 442 * Same as chppAppInit(), but specifies the client/service endpoints to be 443 * enabled. 444 * 445 * @param appContext Maintains status for each app layer instance. 446 * @param transportContext The transport layer status struct associated with 447 * this app layer instance. 448 * @param clientServiceSet Bitmap specifying the client/service endpoints to be 449 * enabled. 450 */ 451 void chppAppInitWithClientServiceSet( 452 struct ChppAppState *appContext, 453 struct ChppTransportState *transportContext, 454 struct ChppClientServiceSet clientServiceSet); 455 456 /** 457 * Deinitializes the CHPP app layer for e.g. clean shutdown. 458 * 459 * @param appContext A non-null pointer to ChppAppState initialized previously 460 * in chppAppInit(). 461 */ 462 void chppAppDeinit(struct ChppAppState *appContext); 463 464 /** 465 * Processes an Rx Datagram from the transport layer. 466 * 467 * @param context Maintains status for each app layer instance. 468 * @param buf Input data. Cannot be null. 469 * @param len Length of input data in bytes. 470 */ 471 void chppAppProcessRxDatagram(struct ChppAppState *context, uint8_t *buf, 472 size_t len); 473 474 /** 475 * Used by the transport layer to notify the app layer of a reset during 476 * operation. This function is called after the transport layer has sent a reset 477 * or reset-ack packet. 478 * In turn, this function notifies clients and services to allow them to reset 479 * or recover state as necessary. 480 * 481 * @param context Maintains status for each app layer instance. 482 */ 483 void chppAppProcessReset(struct ChppAppState *context); 484 485 /** 486 * Convert UUID to a human-readable, null-terminated string. 487 * 488 * @param uuid Input UUID 489 * @param strOut Output null-terminated string 490 */ 491 void chppUuidToStr(const uint8_t uuid[CHPP_SERVICE_UUID_LEN], 492 char strOut[CHPP_SERVICE_UUID_STRING_LEN]); 493 494 /** 495 * Maps a CHPP app layer error to a CHRE error. 496 * 497 * @param chppError CHPP app layer error (from enum ChppAppErrorCode). 498 * 499 * @return CHRE error (from enum chreError). 500 */ 501 uint8_t chppAppErrorToChreError(uint8_t error); 502 503 #ifdef __cplusplus 504 } 505 #endif 506 507 #endif // CHPP_APP_H_ 508