/** * \file mesh_services.c * * Generic Module to handle both * - Mesh Provisioning Service :: 0x1827 * - Mesh Proxy Service :: 0x1828 */ /* * Copyright (C) 2018. Mindtree Limited. * All rights reserved. */ #include "mesh_services.h" /********************************************************************* * GLOBAL VARIABLES */ /* Mesh Prov Service UUID: 0x1827 */ CONST uint8 mesh_prov_UUID[ATT_BT_UUID_SIZE] = { LO_UINT16(MESH_PROV_SERVICE_UUID), HI_UINT16(MESH_PROV_SERVICE_UUID) }; /* Mesh Prov Data IN UUID: 0x2ADB */ CONST uint8 mesh_prov_data_in_UUID[ATT_BT_UUID_SIZE] = { LO_UINT16(MESH_PROV_DATA_IN_UUID), HI_UINT16(MESH_PROV_DATA_IN_UUID) }; /* Mesh Prov Data OUT UUID: 0x2ADC */ CONST uint8 mesh_prov_data_out_UUID[ATT_BT_UUID_SIZE] = { LO_UINT16(MESH_PROV_DATA_OUT_UUID), HI_UINT16(MESH_PROV_DATA_OUT_UUID) }; /* Mesh Proxy Service UUID: 0x1828 */ CONST uint8 mesh_proxy_UUID[ATT_BT_UUID_SIZE] = { LO_UINT16(MESH_PROXY_SERVICE_UUID), HI_UINT16(MESH_PROXY_SERVICE_UUID) }; /* Mesh Proxy Data IN UUID: 0x2ADD */ CONST uint8 mesh_proxy_data_in_UUID[ATT_BT_UUID_SIZE] = { LO_UINT16(MESH_PROXY_DATA_IN_UUID), HI_UINT16(MESH_PROXY_DATA_IN_UUID) }; /* Mesh Proxy Data OUT UUID: 0x2ADE */ CONST uint8 mesh_proxy_data_out_UUID[ATT_BT_UUID_SIZE] = { LO_UINT16(MESH_PROXY_DATA_OUT_UUID), HI_UINT16(MESH_PROXY_DATA_OUT_UUID) }; /********************************************************************* * EXTERNAL VARIABLES */ /********************************************************************* * EXTERNAL FUNCTIONS */ /********************************************************************* * LOCAL VARIABLES */ /* Mesh Provisioning Service Related Callbacks */ static mesh_prov_cb * prov_cb; /* Mesh Proxy Service Related Callbacks */ static mesh_proxy_cb * proxy_cb; /********************************************************************* * Profile Attributes - variables */ /* Mesh Provisioning Service */ static CONST gattAttrType_t mesh_prov_service = {ATT_BT_UUID_SIZE, mesh_prov_UUID}; /* Mesh Prov Data IN Properties */ static uint8 mesh_prov_data_in_props = GATT_PROP_WRITE_NO_RSP; /* Mesh Prov Data IN Value */ static uint8 mesh_prov_data_in_val[20]; /* Mesh Prov Data OUT Properties */ static uint8 mesh_prov_data_out_props = GATT_PROP_NOTIFY; /* Mesh Prov Data OUT Value */ static uint8 mesh_prov_data_out_val[20]; /* Mesh Prov Data OUT CCCD value array */ static gattCharCfg_t mesh_prov_data_out_cccd[GATT_MAX_NUM_CONN]; /* Mesh Proxy Service */ static CONST gattAttrType_t mesh_proxy_service = {ATT_BT_UUID_SIZE, mesh_proxy_UUID}; /* Mesh Proxy Data IN Properties */ static uint8 mesh_proxy_data_in_props = GATT_PROP_WRITE_NO_RSP; /* Mesh Proxy Data IN Value */ static uint8 mesh_proxy_data_in_val[20]; /* Mesh Proxy Data OUT Properties */ static uint8 mesh_proxy_data_out_props = GATT_PROP_NOTIFY; /* Mesh Proxy Data OUT Value */ static uint8 mesh_proxy_data_out_val[20]; /* Mesh Proxy Data OUT CCCD value array */ static gattCharCfg_t mesh_proxy_data_out_cccd[GATT_MAX_NUM_CONN]; /********************************************************************* * Profile Attributes - Table */ /* Mesh Provisioning Service Attribute Table */ static gattAttribute_t mesh_prov_attr_tbl[MESH_PROV_IDX_NB] = { /* Mesh Provisioning Service Declaration */ { { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */ GATT_PERMIT_READ, /* permissions */ 0, /* handle */ (uint8 *)&mesh_prov_service /* pValue */ }, /* Mesh Prov Data IN Characteristic Declaration */ { { ATT_BT_UUID_SIZE, characterUUID }, GATT_PERMIT_READ, 0, &mesh_prov_data_in_props }, /* Mesh Prov Data IN Characteristic Value */ { { ATT_BT_UUID_SIZE, mesh_prov_data_in_UUID }, GATT_PERMIT_WRITE, 0, &mesh_prov_data_in_val[0] }, /* Mesh Prov Data OUT Characteristic Declaration */ { { ATT_BT_UUID_SIZE, characterUUID }, GATT_PERMIT_READ, 0, &mesh_prov_data_out_props }, /* Mesh Prov Data OUT Characteristic Value */ { { ATT_BT_UUID_SIZE, mesh_prov_data_out_UUID }, 0, 0, &mesh_prov_data_out_val[0] }, /* Mesh Prov Data OUT CCCD */ { { ATT_BT_UUID_SIZE, clientCharCfgUUID }, GATT_PERMIT_READ | GATT_PERMIT_WRITE, 0, (uint8 *) &mesh_prov_data_out_cccd }, }; /* Mesh Proxy Service Attribute Table */ static gattAttribute_t mesh_proxy_attr_tbl[MESH_PROXY_IDX_NB] = { /* Mesh Proxy Service Declaration */ { { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */ GATT_PERMIT_READ, /* permissions */ 0, /* handle */ (uint8 *)&mesh_proxy_service /* pValue */ }, /* Mesh Proxy Data IN Characteristic Declaration */ { { ATT_BT_UUID_SIZE, characterUUID }, GATT_PERMIT_READ, 0, &mesh_proxy_data_in_props }, /* Mesh Proxy Data IN Characteristic Value */ { { ATT_BT_UUID_SIZE, mesh_proxy_data_in_UUID }, GATT_PERMIT_WRITE, 0, &mesh_proxy_data_in_val[0] }, /* Mesh Proxy Data OUT Characteristic Declaration */ { { ATT_BT_UUID_SIZE, characterUUID }, GATT_PERMIT_READ, 0, &mesh_proxy_data_out_props }, /* Mesh Proxy Data OUT Characteristic Value */ { { ATT_BT_UUID_SIZE, mesh_proxy_data_out_UUID }, 0, 0, &mesh_proxy_data_out_val[0] }, /* Mesh Proxy Data OUT CCCD */ { { ATT_BT_UUID_SIZE, clientCharCfgUUID }, GATT_PERMIT_READ | GATT_PERMIT_WRITE, 0, (uint8 *) &mesh_proxy_data_out_cccd }, }; /********************************************************************* * LOCAL FUNCTIONS */ static bStatus_t mesh_prov_write_cb ( uint16 connHandle, gattAttribute_t *pAttr, uint8 *pValue, uint8 len, uint16 offset ); static bStatus_t mesh_proxy_write_cb ( uint16 connHandle, gattAttribute_t *pAttr, uint8 *pValue, uint8 len, uint16 offset ); static void mesh_prov_handle_conn ( uint16 connHandle, uint8 changeType ); static void mesh_proxy_handle_conn ( uint16 connHandle, uint8 changeType ); /********************************************************************* * PROFILE CALLBACKS */ /* Mesh Provisioning Service Internal Callbacks */ CONST gattServiceCBs_t mesh_prov_internal_cbs = { NULL, // Read callback function pointer mesh_prov_write_cb, // Write callback function pointer NULL // Authorization callback function pointer }; /* Mesh Proxy Service Internal Callbacks */ CONST gattServiceCBs_t mesh_proxy_internal_cbs = { NULL, // Read callback function pointer mesh_proxy_write_cb, // Write callback function pointer NULL // Authorization callback function pointer }; /* ---------------------------------------------------------------------------- * Function : bStatus_t mesh_prov_init(mesh_prov_cb *cb) * ---------------------------------------------------------------------------- * Description : Send request to add Mesh Provisioning Service[0x1827] * into the attribute database. * Defines the different access functions .* (setter/getter commands to access the different * characteristic attributes). * Inputs : Pointer to mesh_prov_cb. * Outputs : bStatus_t : SUCCESS or failure reasons * Assumptions : None * ------------------------------------------------------------------------- */ bStatus_t mesh_prov_init(mesh_prov_cb *cb) { uint8 status = FAILURE; /* Initialize Client Characteristic Configuration attributes */ GATTServApp_InitCharCfg ( INVALID_CONNHANDLE, mesh_prov_data_out_cccd ); /* Register with Link DB to receive link status change callback */ VOID linkDB_Register(mesh_prov_handle_conn); /* Register GATT attribute list and CBs with GATT Server App */ status = GATTServApp_RegisterService ( mesh_prov_attr_tbl, GATT_NUM_ATTRS(mesh_prov_attr_tbl), &mesh_prov_internal_cbs ); /* Save the Callback Provided */ prov_cb = cb; return (status); } /* ---------------------------------------------------------------------------- * Function : bStatus_t mesh_proxy_init(mesh_proxy_cb *cb) * ---------------------------------------------------------------------------- * Description : Send request to add Mesh Proxy Service[0x1828] * into the attribute database. * Defines the different access functions .* (setter/getter commands to access the different * characteristic attributes). * Inputs : Pointer to mesh_proxy_cb. * Outputs : bStatus_t : SUCCESS or failure reasons * Assumptions : None * ------------------------------------------------------------------------- */ bStatus_t mesh_proxy_init(mesh_proxy_cb *cb) { uint8 status = FAILURE; /* Initialize Client Characteristic Configuration attributes */ GATTServApp_InitCharCfg ( INVALID_CONNHANDLE, mesh_proxy_data_out_cccd ); /* Register with Link DB to receive link status change callback */ VOID linkDB_Register(mesh_proxy_handle_conn); /* Register GATT attribute list and CBs with GATT Server App */ status = GATTServApp_RegisterService ( mesh_proxy_attr_tbl, GATT_NUM_ATTRS(mesh_proxy_attr_tbl), &mesh_proxy_internal_cbs ); /* Save the Callback Provided */ proxy_cb = cb; return (status); } /* ---------------------------------------------------------------------------- * Function : bStatus_t mesh_prov_deinit(void) * ---------------------------------------------------------------------------- * Description : Send request to delete Mesh Provisioning Service[0x1827] * from the attribute database. * Inputs : None * Outputs : bStatus_t : SUCCESS or failure reasons * Assumptions : None * ------------------------------------------------------------------------- */ bStatus_t mesh_prov_deinit(void) { uint8 status = SUCCESS; /* Reset the Callback Provided */ prov_cb = NULL; /** * Deregister Mesh Prov Service attribute list and * CBs from GATT Server Application */ status = GATTServApp_DeregisterService ( GATT_SERVICE_HANDLE(mesh_prov_attr_tbl), NULL ); return ( status ); } /* ---------------------------------------------------------------------------- * Function : bStatus_t mesh_proxy_deinit(void) * ---------------------------------------------------------------------------- * Description : Send request to delete Mesh Proxy Service[0x1828] * from the attribute database. * Inputs : None * Outputs : bStatus_t : SUCCESS or failure reasons * Assumptions : None * ------------------------------------------------------------------------- */ bStatus_t mesh_proxy_deinit(void) { uint8 status = SUCCESS; /* Reset the Callback Provided */ proxy_cb = NULL; /** * Deregister Mesh Prov Service attribute list and * CBs from GATT Server Application */ status = GATTServApp_DeregisterService ( GATT_SERVICE_HANDLE(mesh_proxy_attr_tbl), NULL ); return ( status ); } /* ---------------------------------------------------------------------------- * Function : bStatus_t mesh_prov_notify_data_out(uint16 conn_hndl, * uint8 attidx, uint8 *val, uint8 val_len) * ---------------------------------------------------------------------------- * Description : Send Mesh Provisiong Data Out notification to Peer * Inputs : - conn_hndl - connection index * - attidx - index to attributes in the service * - val - pointer to value * - val_len - length of value * Outputs : bStatus_t : SUCCESS or failure reasons * Assumptions : None * ------------------------------------------------------------------------- */ bStatus_t mesh_prov_notify_data_out ( uint16 conn_hndl, uint8 attidx, uint8 * val, uint8 val_len ) { attHandleValueNoti_t mesh_prov_notif; uint16 value = GATTServApp_ReadCharCfg ( conn_hndl, mesh_prov_data_out_cccd ); /* NOTE: Currently the attidx is ignored */ (void)attidx; /* Assign the Mesh Prov Data Out Value Handle */ mesh_prov_notif.handle =\ mesh_prov_attr_tbl[MESH_PROV_DATA_OUT_VALUE_VAL].handle; /* Copy the Value and Length */ mesh_prov_notif.len = val_len; osal_memcpy(mesh_prov_notif.value, val, val_len); /* If notifications enabled */ if ( value & GATT_CLIENT_CFG_NOTIFY ) { /* Send the notification */ return GATT_Notification( conn_hndl, &mesh_prov_notif, FALSE ); } return bleIncorrectMode; } /* ---------------------------------------------------------------------------- * Function : bStatus_t mesh_proxy_notify_data_out(uint16 conn_hndl, * uint8 attidx, uint8 *val, uint8 val_len) * ---------------------------------------------------------------------------- * Description : Send Mesh Proxy Data Out notification to Peer * Inputs : - conn_hndl - connection index * - attidx - index to attributes in the service * - val - pointer to value * - val_len - length of value * Outputs : bStatus_t : SUCCESS or failure reasons * Assumptions : None * ------------------------------------------------------------------------- */ bStatus_t mesh_proxy_notify_data_out ( uint16 conn_hndl, uint8 attidx, uint8 * val, uint8 val_len ) { attHandleValueNoti_t mesh_proxy_notif; uint16 value = GATTServApp_ReadCharCfg ( conn_hndl, mesh_proxy_data_out_cccd ); /* NOTE: Currently the attidx is ignored */ (void)attidx; /* Assign the Mesh Prov Data Out Value Handle */ mesh_proxy_notif.handle =\ mesh_proxy_attr_tbl[MESH_PROV_DATA_OUT_VALUE_VAL].handle; /* Copy the Value and Length */ mesh_proxy_notif.len = val_len; osal_memcpy(mesh_proxy_notif.value, val, val_len); /* If notifications enabled */ if ( value & GATT_CLIENT_CFG_NOTIFY ) { /* Send the notification */ return GATT_Notification( conn_hndl, &mesh_proxy_notif, FALSE ); } return bleIncorrectMode; } /* ---------------------------------------------------------------------------- * Function : bStatus_t mesh_prov_write_cb (uint16 connHandle, gattAttribute_t * pAttr, uint8 * pValue, uint8 len, uint16 offset) * ---------------------------------------------------------------------------- * Description : Validate attribute data prior to a write operation * Inputs : - connHandle - connection Handle * - pAttr - pointer to attribute * - pValue - pointer to data to be written * - len - length of data * - offset - offset of the first octet to be written * Outputs : Success or Failure * Assumptions : None * ------------------------------------------------------------------------- */ static bStatus_t mesh_prov_write_cb ( uint16 connHandle, gattAttribute_t * pAttr, uint8 * pValue, uint8 len, uint16 offset ) { bStatus_t status = SUCCESS; /* If attribute permissions require authorization to write, return error */ if ( gattPermitAuthorWrite( pAttr->permissions ) ) { /* Insufficient authorization */ return ( ATT_ERR_INSUFFICIENT_AUTHOR ); } if ( pAttr->type.len == ATT_BT_UUID_SIZE ) { /* 16-bit UUID */ uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); switch (uuid) { case MESH_PROV_DATA_IN_UUID: /* Validate the value */ /* Make sure it's not a blob oper */ /* phy_printf("\r\n MESH_PROV_DATA_IN WWR of length %d\r\n", len); */ if ( offset != 0 ) { status = ATT_ERR_ATTR_NOT_LONG; } /* Write the value */ if (SUCCESS == status) { /* TODO: Check if this is needed */ /* len = (len <= MESH_PROV_DATA_IN_MAX_LENGTH) ?\ len : MESH_PROV_DATA_IN_MAX_LENGTH; */ /* Notify Data IN Write Callback */ /* Invoke Data IN Callback */ if (NULL != prov_cb) { prov_cb->prov_data_in_cb ( connHandle, offset, len, pValue ); } } break; case GATT_CLIENT_CHAR_CFG_UUID: /* phy_printf("\r\n MESH_PROV_DATA_OUT CCCD Write for %d Attr Handle of length %d\r\n", pAttr->handle, len); */ status = GATTServApp_ProcessCCCWriteReq ( connHandle, pAttr, pValue, len, offset, GATT_CLIENT_CFG_NOTIFY ); if ( status == SUCCESS ) { uint16 t_cccd_val = BUILD_UINT16( pValue[0], pValue[1] ); t_cccd_val = (GATT_CLIENT_CFG_NOTIFY == t_cccd_val) ?\ TRUE : FALSE; /* Invoke CCCD Update Callback */ if (NULL != prov_cb) { prov_cb->prov_data_out_ccd_cb ( connHandle, t_cccd_val ); } } break; default: status = ATT_ERR_ATTR_NOT_FOUND; break; } } else { // 128-bit UUID status = ATT_ERR_INVALID_HANDLE; } return ( status ); } /* ---------------------------------------------------------------------------- * Function : bStatus_t mesh_proxy_write_cb (uint16 connHandle, gattAttribute_t * pAttr, uint8 * pValue, uint8 len, uint16 offset) * ---------------------------------------------------------------------------- * Description : Validate attribute data prior to a write operation * Inputs : - connHandle - connection Handle * - pAttr - pointer to attribute * - pValue - pointer to data to be written * - len - length of data * - offset - offset of the first octet to be written * Outputs : Success or Failure * Assumptions : None * ------------------------------------------------------------------------- */ static bStatus_t mesh_proxy_write_cb ( uint16 connHandle, gattAttribute_t * pAttr, uint8 * pValue, uint8 len, uint16 offset ) { bStatus_t status = SUCCESS; /* If attribute permissions require authorization to write, return error */ if ( gattPermitAuthorWrite( pAttr->permissions ) ) { /* Insufficient authorization */ return ( ATT_ERR_INSUFFICIENT_AUTHOR ); } if ( pAttr->type.len == ATT_BT_UUID_SIZE ) { /* 16-bit UUID */ uint16 uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]); switch (uuid) { case MESH_PROXY_DATA_IN_UUID: /* Validate the value */ /* Make sure it's not a blob oper */ /* phy_printf("\r\n MESH_PROXY_DATA_IN WWR of length %d\r\n", len); */ if ( offset != 0 ) { status = ATT_ERR_ATTR_NOT_LONG; } /* Write the value */ if (SUCCESS == status) { /* TODO: Check if this is needed */ /* len = (len <= MESH_PROXY_DATA_IN_MAX_LENGTH) ?\ len : MESH_PROXY_DATA_IN_MAX_LENGTH; */ /* Notify Data IN Write Callback */ /* Invoke Data IN Callback */ if (NULL != proxy_cb) { proxy_cb->proxy_data_in_cb ( connHandle, offset, len, pValue ); } } break; case GATT_CLIENT_CHAR_CFG_UUID: /* phy_printf("\r\n MESH_PROXY_DATA_OUT CCCD Write for %d Attr Handle of length %d\r\n", pAttr->handle, len); */ status = GATTServApp_ProcessCCCWriteReq ( connHandle, pAttr, pValue, len, offset, GATT_CLIENT_CFG_NOTIFY ); if ( status == SUCCESS ) { uint16 t_cccd_val = BUILD_UINT16( pValue[0], pValue[1] ); t_cccd_val = (GATT_CLIENT_CFG_NOTIFY == t_cccd_val) ?\ TRUE : FALSE; /* Invoke CCCD Update Callback */ if (NULL != proxy_cb) { proxy_cb->proxy_data_out_ccd_cb ( connHandle, t_cccd_val ); } } break; default: status = ATT_ERR_ATTR_NOT_FOUND; break; } } else { // 128-bit UUID status = ATT_ERR_INVALID_HANDLE; } return ( status ); } /* ---------------------------------------------------------------------------- * Function : void mesh_prov_handle_conn(uint16 connHandle, * uint8 changeType) * ---------------------------------------------------------------------------- * Description : Callback to Handle Mesh Prov Connection event * Inputs : - connHandle - connection Handle * - changeType - type of change * Outputs : None * Assumptions : None * ------------------------------------------------------------------------- */ static void mesh_prov_handle_conn( uint16 connHandle, uint8 changeType ) { // Make sure this is not loopback connection if ( connHandle != LOOPBACK_CONNHANDLE ) { // Reset Client Char Config if connection has dropped if ( ( changeType == LINKDB_STATUS_UPDATE_REMOVED ) || ( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) && ( !linkDB_Up( connHandle ) ) ) ) { GATTServApp_InitCharCfg( connHandle, mesh_prov_data_out_cccd ); } } } /* ---------------------------------------------------------------------------- * Function : void mesh_proxy_handle_conn(uint16 connHandle, * uint8 changeType) * ---------------------------------------------------------------------------- * Description : Callback to Handle Mesh Proxy Connection event * Inputs : - connHandle - connection Handle * - changeType - type of change * Outputs : None * Assumptions : None * ------------------------------------------------------------------------- */ static void mesh_proxy_handle_conn( uint16 connHandle, uint8 changeType ) { // Make sure this is not loopback connection if ( connHandle != LOOPBACK_CONNHANDLE ) { // Reset Client Char Config if connection has dropped if ( ( changeType == LINKDB_STATUS_UPDATE_REMOVED ) || ( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) && ( !linkDB_Up( connHandle ) ) ) ) { GATTServApp_InitCharCfg( connHandle, mesh_proxy_data_out_cccd ); } } }