blob: f1e8e7206f75c7bb50d340ba638aedc4bc6a5d21 [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef CHPP_APP_H_
#define CHPP_APP_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "chpp/macros.h"
#include "chpp/transport.h"
#ifdef __cplusplus
extern "C" {
#endif
/************************************************
* Public Definitions
***********************************************/
/**
* Maximum number of services that can be registered by CHPP (not including
* predefined services), if not defined by the build system.
*/
#ifndef CHPP_MAX_REGISTERED_SERVICES
#define CHPP_MAX_REGISTERED_SERVICES 5
#endif
/**
* Maximum number of clients that can be registered by CHPP (not including
* predefined clients), if not defined by the build system.
*/
#ifndef CHPP_MAX_REGISTERED_CLIENTS
#define CHPP_MAX_REGISTERED_CLIENTS 5
#endif
/**
* Maximum number of services that can be discovered by CHPP (not including
* predefined services), if not defined by the build system.
*/
#ifndef CHPP_MAX_DISCOVERED_SERVICES
#define CHPP_MAX_DISCOVERED_SERVICES \
MAX(CHPP_MAX_REGISTERED_SERVICES, CHPP_MAX_REGISTERED_CLIENTS)
#endif
/**
* Default value for reserved fields.
*/
#define CHPP_RESERVED 0
/**
* Client index number when there is no matching client
*/
#define CHPP_CLIENT_INDEX_NONE 0xff
/**
* Handle Numbers in ChppAppHeader
*/
enum ChppHandleNumber {
//! Handleless communication
CHPP_HANDLE_NONE = 0x00,
//! Loopback Service
CHPP_HANDLE_LOOPBACK = 0x01,
//! Discovery Service
CHPP_HANDLE_DISCOVERY = 0x0F,
//! Negotiated Services (starting from this offset)
CHPP_HANDLE_NEGOTIATED_RANGE_START = 0x10,
};
/**
* Message Types as used in ChppAppHeader
*/
#define CHPP_APP_MASK_MESSAGE_TYPE LEAST_SIGNIFICANT_NIBBLE
#define CHPP_APP_GET_MESSAGE_TYPE(value) \
((enum ChppMessageType)( \
(value)&CHPP_APP_MASK_MESSAGE_TYPE)) // TODO: Consider checking if this
// maps into a valid enum
enum ChppMessageType {
//! Request from client. Needs response from service.
CHPP_MESSAGE_TYPE_CLIENT_REQUEST = 0,
//! Response from service (with the same Command and Transaction ID as the
//! client request).
CHPP_MESSAGE_TYPE_SERVICE_RESPONSE = 1,
//! Notification from client. Service shall not respond.
CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION = 2,
//! Notification from service. Client shall not respond.
CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION = 3,
};
/**
* Error codes used by the app layer / clients / services.
*/
enum ChppAppErrorCode {
//! Success (no error)
CHPP_APP_ERROR_NONE = 0,
//! Invalid command
CHPP_APP_ERROR_INVALID_COMMAND = 1,
//! Invalid argument(s)
CHPP_APP_ERROR_INVALID_ARG = 2,
//! Busy
CHPP_APP_ERROR_BUSY = 3,
//! Out of memory
CHPP_APP_ERROR_OOM = 4,
//! Feature not supported
CHPP_APP_ERROR_UNSUPPORTED = 5,
//! Timeout
CHPP_APP_ERROR_TIMEOUT = 6,
//! Functionality disabled (e.g. per user configuration)
CHPP_APP_ERROR_DISABLED = 7,
//! Rate limit exceeded (try again later)
CHPP_APP_ERROR_RATELIMITED = 8,
//! Function in use / blocked by another entity (e.g. the AP)
CHPP_APP_ERROR_BLOCKED = 9,
//! Invalid length
CHPP_APP_ERROR_INVALID_LENGTH = 10,
//! Unspecified failure
CHPP_APP_ERROR_UNSPECIFIED = 255
};
/**
* CHPP Application Layer header
*/
CHPP_PACKED_START
struct ChppAppHeader {
//! Service Handle
uint8_t handle;
//! Most significant nibble (MSN): Reserved
//! Least significant nibble (LSN): Message Type from enum ChppMessageType
uint8_t type;
//! Transaction ID
uint8_t transaction;
//! Error if any, from enum ChppAppErrorCode
uint8_t error;
//! Command
uint16_t command;
} CHPP_PACKED_ATTR;
CHPP_PACKED_END
//! Minimum length of a header that includes upto the transaction ID
#define CHPP_APP_MIN_LEN_HEADER_WITH_TRANSACTION (3 * sizeof(uint8_t))
/**
* Function type that dispatches incoming datagrams for any client or service
*/
typedef enum ChppAppErrorCode(ChppDispatchFunction)(void *context, uint8_t *buf,
size_t len);
/**
* Function type that initializes a client and assigns it its handle number
*/
typedef bool(ChppClientInitFunction)(void *context, uint8_t handle,
struct ChppVersion serviceVersion);
/**
* Function type that deinitializes a client.
*/
typedef void(ChppClientDeinitFunction)(void *context);
/**
* Length of a service UUID and its human-readable printed form in bytes
*/
#define CHPP_SERVICE_UUID_LEN 16
#define CHPP_SERVICE_UUID_STRING_LEN (16 * 2 + 4 + 1)
/**
* Length of a version number, in bytes (major + minor + revision), per CHPP
* spec.
*/
#define CHPP_SERVICE_VERSION_LEN (1 + 1 + 2)
/**
* Maximum length of a human-readable service name, per CHPP spec.
* (15 ASCII characters + null)
*/
#define CHPP_SERVICE_NAME_MAX_LEN (15 + 1)
/**
* CHPP definition of a service descriptor as sent over the wire.
*/
CHPP_PACKED_START
struct ChppServiceDescriptor {
//! UUID of the service.
//! Must be generated according to RFC 4122, UUID version 4 (random).
uint8_t uuid[CHPP_SERVICE_UUID_LEN];
//! Human-readable name of the service for debugging.
char name[CHPP_SERVICE_NAME_MAX_LEN];
//! Version of the service.
struct ChppVersion version;
} CHPP_PACKED_ATTR;
CHPP_PACKED_END
/**
* CHPP definition of a service as supported on a server.
*/
struct ChppService {
//! Service Descriptor as sent over the wire.
struct ChppServiceDescriptor descriptor;
//! Pointer to the function that dispatches incoming client requests for the
//! service.
ChppDispatchFunction *requestDispatchFunctionPtr;
//! Pointer to the function that dispatches incoming client notifications for
//! the service.
ChppDispatchFunction *notificationDispatchFunctionPtr;
//! Minimum valid length of datagrams for the service.
size_t minLength;
};
/**
* CHPP definition of a client descriptor.
*/
struct ChppClientDescriptor {
//! UUID of the client.
//! Must be generated according to RFC 4122, UUID version 4 (random).
uint8_t uuid[CHPP_SERVICE_UUID_LEN];
//! Version of the client.
struct ChppVersion version;
};
/**
* CHPP definition of a client.
*/
struct ChppClient {
//! Client descriptor.
struct ChppClientDescriptor descriptor;
//! Pointer to the function that dispatches incoming service responses for the
//! client.
ChppDispatchFunction *responseDispatchFunctionPtr;
//! Pointer to the function that dispatches incoming service notifications for
//! the client.
ChppDispatchFunction *notificationDispatchFunctionPtr;
//! Pointer to the function that initializes the client (after it is matched
//! with a service at discovery) and assigns it its handle number.
ChppClientInitFunction *initFunctionPtr;
//! Pointer to the function that deinitializes the client.
ChppClientDeinitFunction *deinitFunctionPtr;
//! Minimum valid length of datagrams for the service.
size_t minLength;
};
/**
* Maintains the basic state for each request/response functionality of a
* client or service.
* Any number of these may be included in the (context) status variable of a
* client or service (one per every every request/response functionality).
*/
struct ChppRequestResponseState {
uint64_t requestTime; // Time of the last request
uint64_t responseTime; // Time of the last response
uint8_t transaction; // Transaction ID for the last request/response
};
struct ChppClientServiceSet {
bool wifiService : 1;
bool gnssService : 1;
bool wwanService : 1;
bool wifiClient : 1;
bool gnssClient : 1;
bool wwanClient : 1;
bool loopbackClient : 1;
};
struct ChppAppState {
struct ChppTransportState *transportContext; // Pointing to transport context
const struct chrePalSystemApi *systemApi; // Pointing to the PAL system APIs
uint8_t registeredServiceCount; // Number of services currently registered
const struct ChppService *registeredServices[CHPP_MAX_REGISTERED_SERVICES];
void *registeredServiceContexts[CHPP_MAX_REGISTERED_SERVICES];
uint8_t registeredClientCount; // Number of services currently registered
const struct ChppClient *registeredClients[CHPP_MAX_REGISTERED_CLIENTS];
void *registeredClientContexts[CHPP_MAX_REGISTERED_CLIENTS];
uint8_t
clientIndexOfServiceIndex[CHPP_MAX_DISCOVERED_SERVICES]; // Lookup table
struct ChppClientServiceSet clientServiceSet; // Enabled client/services
};
#define CHPP_SERVICE_INDEX_OF_HANDLE(handle) \
((handle)-CHPP_HANDLE_NEGOTIATED_RANGE_START)
#define CHPP_SERVICE_HANDLE_OF_INDEX(index) \
((index) + CHPP_HANDLE_NEGOTIATED_RANGE_START)
/************************************************
* Public functions
***********************************************/
/**
* Initializes the CHPP app layer state stored in the parameter appContext.
* It is necessary to initialize state for each app layer instance on
* every platform.
*
* @param appContext Maintains status for each app layer instance.
* @param transportContext The transport layer status struct associated with
* this app layer instance.
*/
void chppAppInit(struct ChppAppState *appContext,
struct ChppTransportState *transportContext);
/**
* Same as chppAppInit(), but specifies the client/service endpoints to be
* enabled.
*/
void chppAppInitWithClientServiceSet(
struct ChppAppState *appContext,
struct ChppTransportState *transportContext,
struct ChppClientServiceSet clientServiceSet);
/**
* Deinitializes the CHPP app layer for e.g. clean shutdown.
*
* @param appContext A non-null pointer to ChppAppState initialized previously
* in chppAppInit().
*/
void chppAppDeinit(struct ChppAppState *appContext);
/*
* Processes an Rx Datagram from the transport layer.
*
* @param context Maintains status for each app layer instance.
* @param buf Input data. Cannot be null.
* @param len Length of input data in bytes.
*/
void chppProcessRxDatagram(struct ChppAppState *context, uint8_t *buf,
size_t len);
/**
* Convert UUID to a human-readable, null-terminated string.
*
* @param uuid Input UUID
* @param strOut Output null-terminated string
*/
void chppUuidToStr(const uint8_t uuid[CHPP_SERVICE_UUID_LEN],
char strOut[CHPP_SERVICE_UUID_STRING_LEN]);
#ifdef __cplusplus
}
#endif
#endif // CHPP_APP_H_