Пример #1
0
//--------------------------------------------------------------------------------------------------
static void OperationHandler
(
    pa_avc_LWM2MOperationDataRef_t opRef

)
{
    pa_avc_OpType_t opType;
    const char* objPrefixPtr;
    int objId;
    int objInstId;
    int resourceId;
    const uint8_t* payloadPtr;
    const uint8_t* tokenPtr;
    uint8_t tokenLength;
    size_t payloadLength;

    // Get the operation details from the opRef
    opType = pa_avc_GetOpType(opRef);
    pa_avc_GetOpAddress(opRef, &objPrefixPtr, &objId, &objInstId, &resourceId);
    pa_avc_GetOpPayload(opRef, &payloadPtr, &payloadLength);

    pa_avc_GetOpToken(opRef, &tokenPtr, &tokenLength);

    le_result_t result;
    assetData_InstanceDataRef_t instRef;
    int instId;
    pa_avc_OpErr_t opErr = PA_AVC_OPERR_NO_ERROR;

    // In some cases, we need to adjust the prefix string.
    const char* newPrefixPtr = objPrefixPtr;

    // Empty object prefix string should use 'lwm2m' when accessing assetData.
    // TODO: This is a work-around because the modem currently does not handle the 'lwm2m' prefix.
    if ( strlen(objPrefixPtr) == 0 )
    {
        newPrefixPtr = "lwm2m";
        LE_INFO("Defaulting to lwm2m namespace for assetData");
    }
    // Apps will have an "le_" prefix, which needs to be stripped, because the "le_" is not part
    // of the app name that is stored in assetData.
    // TODO: Should the "le_" prefix instead be added to the app name in assetData?
    else if ( strncmp(objPrefixPtr, "le_", 3) == 0 )
    {
        newPrefixPtr = objPrefixPtr+3;
        LE_DEBUG("Adjusting %s to %s", objPrefixPtr, newPrefixPtr);
    }

    LE_DEBUG("Operation: %s/%d/%d/%d <%d>", newPrefixPtr, objId, objInstId, resourceId, opType);

    // Reinitailize CurrentReadResId to an invalid value.
    if ( opType != PA_AVC_OPTYPE_READ )
    {
        CurrentReadResId = INVALID_RESOURCE_ID;
    }

    // Special handling for READ if object instance is not specified (-1)
    // TODO: restructure
    if ( (opType == PA_AVC_OPTYPE_READ) && (objInstId == -1) )
    {
        LE_DEBUG("PA_AVC_OPTYPE_READ %s/%d", newPrefixPtr, objId);

        assetData_AssetDataRef_t assetRef;

        result = assetData_GetAssetRefById(newPrefixPtr, objId, &assetRef);

        if ( result == LE_NOT_FOUND )
            opErr = PA_AVC_OPERR_OBJ_UNSUPPORTED;
        else if ( result != LE_OK )
            opErr = PA_AVC_OPERR_INTERNAL;

        if ( opErr != PA_AVC_OPERR_NO_ERROR )
        {
            pa_avc_OperationReportError(opRef, opErr);
            return;
        }

        // Read the asset data only when the request is for the first block. For subsequent block
        // reads, return asset data stored in the buffer. It is assumed that unless the read
        // of the first block is successful, no subsequent requests will be made by the server.
        if ( pa_avc_IsFirstBlock(opRef) )
        {
            CurrentReadResId = resourceId;
            CurrentReadAssetRef = assetRef;
            result = assetData_WriteObjectToTLV(assetRef,
                                                resourceId,
                                                ValueData,
                                                sizeof(ValueData),
                                                &BytesWritten);
        }
        else
        {
            // We have received a request for a non-zero block offset before a request for a
            // block offset of 0; this is an error
            if ( resourceId != CurrentReadResId ||
                 assetRef != CurrentReadAssetRef )
            {
                opErr = PA_AVC_OPERR_INTERNAL;
                LE_ERROR("Error reading asset data.");
            }
            else
            {
                result = LE_OK;
            }
        }

        if ( result == LE_OVERFLOW )
            opErr = PA_AVC_OPERR_OVERFLOW;
        else if ( result != LE_OK )
            opErr = PA_AVC_OPERR_INTERNAL;

        if ( opErr != PA_AVC_OPERR_NO_ERROR )
        {
            pa_avc_OperationReportError(opRef, opErr);
        }
        else
        {
            // Send the valid response
            pa_avc_OperationReportSuccess(opRef, ValueData, BytesWritten);
        }

        // TODO: Refactor so I don't need a return here.
        return;
    }

    if ((opType == PA_AVC_OPTYPE_OBSERVE_CANCEL) || (opType == PA_AVC_OPTYPE_OBSERVE_RESET))
    {
        LE_DEBUG("PA_AVC_OPTYPE_OBSERVE_CANCEL %s/%d", newPrefixPtr, objId);

        if (objId == -1)
        {
            // Cancel with an objId of -1 means, cancel observe on all objects.
            assetData_CancelAllObserve();

            pa_avc_OperationReportSuccess(opRef, NULL, 0);
            return;
        }
        else
        {
            assetData_AssetDataRef_t assetRef;
            result = assetData_GetAssetRefById(newPrefixPtr, objId, &assetRef);

            if ( result == LE_NOT_FOUND )
                opErr = PA_AVC_OPERR_OBJ_UNSUPPORTED;
            else if ( result != LE_OK )
                opErr = PA_AVC_OPERR_INTERNAL;

            if ( opErr != PA_AVC_OPERR_NO_ERROR )
            {
                LE_ERROR("Failed to read AssetRef.");
                pa_avc_OperationReportError(opRef, opErr);
                return;
            }

            // Cancel observe on all instances of an object.
            result = assetData_SetObserveAllInstances(assetRef, false, NULL, 0);

            if ( result != LE_OK )
            {
                LE_ERROR("Failed to Cancel Observe.");
                pa_avc_OperationReportError(opRef, PA_AVC_OPERR_INTERNAL);
            }
            else
            {
                // At COAP level observe cancel is a read request from the server with observe
                // option flag set to false. So the reponse for cancel should include TLV for
                // entire object.
                result = assetData_WriteObjectToTLV(assetRef,
                                    resourceId,
                                    ValueData,
                                    sizeof(ValueData),
                                    &BytesWritten);

                if ( result == LE_NOT_FOUND )
                    opErr = PA_AVC_OPERR_OBJ_UNSUPPORTED;
                else if ( result != LE_OK )
                    opErr = PA_AVC_OPERR_INTERNAL;

                if ( opErr != PA_AVC_OPERR_NO_ERROR )
                {
                    LE_ERROR("Failed to write TLV of object.");
                    pa_avc_OperationReportError(opRef, opErr);
                    return;
                }

                LE_INFO("Observe cancelled successfully.");

                // Send the valid response
                pa_avc_OperationReportSuccess(opRef, ValueData, BytesWritten);
            }
            return;
        }
    }

    // Observe with an objId of -1 means, observe all instances.
    if ( (opType == PA_AVC_OPTYPE_OBSERVE) && (objInstId == -1) )
    {
        LE_DEBUG("PA_AVC_OPTYPE_OBSERVE %s/%d", newPrefixPtr, objId);

        // Observe not supported on object "/lwm2m/9".
        if ( (strcmp(newPrefixPtr, "lwm2m") == 0) && (objId == 9) )
        {
            LE_DEBUG("Observe not supported on %s/%d/%d", newPrefixPtr, objId, objInstId);
            pa_avc_OperationReportError(opRef, PA_AVC_OPERR_OP_UNSUPPORTED);
            return;
        }

        assetData_AssetDataRef_t assetRef;

        result = assetData_GetAssetRefById(newPrefixPtr, objId, &assetRef);

        if ( result == LE_NOT_FOUND )
            opErr = PA_AVC_OPERR_OBJ_UNSUPPORTED;
        else if ( result != LE_OK )
            opErr = PA_AVC_OPERR_INTERNAL;

        if ( opErr != PA_AVC_OPERR_NO_ERROR )
        {
            LE_ERROR("Failed to read AssetRef.");
            pa_avc_OperationReportError(opRef, opErr);
            return;
        }

        // Set observe on all instances of an object.
        result = assetData_SetObserveAllInstances(assetRef, true, (uint8_t*)tokenPtr, tokenLength);

        if ( result != LE_OK )
        {
            LE_ERROR("Failed to Set Observe.");
            pa_avc_OperationReportError(opRef, PA_AVC_OPERR_INTERNAL);
        }
        else
        {
            result = assetData_WriteObjectToTLV(assetRef,
                                                resourceId,
                                                ValueData,
                                                sizeof(ValueData),
                                                &BytesWritten);

            if ( result == LE_NOT_FOUND )
                opErr = PA_AVC_OPERR_OBJ_UNSUPPORTED;
            else if ( result != LE_OK )
                opErr = PA_AVC_OPERR_INTERNAL;

            if ( opErr != PA_AVC_OPERR_NO_ERROR )
            {
                LE_ERROR("Failed to write TLV of object.");
                pa_avc_OperationReportError(opRef, opErr);
                return;
            }

            LE_INFO("Observe set successfully.");

            // Send the valid response
            pa_avc_OperationReportSuccess(opRef, ValueData, BytesWritten);
        }

        return;
    }

    // These operations all need a valid instanceRef.  Ensure that the specified instance exists,
    // and get the instanceRef; this check is common across several of the opTypes.
    if ( (opType == PA_AVC_OPTYPE_READ) ||
         (opType == PA_AVC_OPTYPE_WRITE) ||
         (opType == PA_AVC_OPTYPE_EXECUTE) ||
         (opType == PA_AVC_OPTYPE_DELETE))
    {
        result = assetData_GetInstanceRefById(newPrefixPtr, objId, objInstId, &instRef);
        if ( result == LE_NOT_FOUND )
            opErr = PA_AVC_OPERR_OBJ_INST_UNAVAIL;
        else if ( result != LE_OK )
            opErr = PA_AVC_OPERR_INTERNAL;

        if ( opErr != PA_AVC_OPERR_NO_ERROR )
        {
            LE_ERROR("Object instance required for this operation.");
            pa_avc_OperationReportError(opRef, opErr);
            return;
        }
    }

    switch ( opType )
    {
        case PA_AVC_OPTYPE_READ:
            LE_DEBUG("PA_AVC_OPTYPE_READ %s/%d/%d/%d", newPrefixPtr, objId, objInstId, resourceId);

            if ( pa_avc_IsFirstBlock(opRef) )
            {
                CurrentReadResId = resourceId;
                CurrentReadInstRef = instRef;

                if ( resourceId == -1 )
                {
                    result = assetData_WriteFieldListToTLV(instRef,
                                                           ValueData,
                                                           sizeof(ValueData),
                                                           &BytesWritten);
                }
                else
                {
                    result = assetData_server_GetValue(opRef,
                                                       instRef,
                                                       resourceId,
                                                       (char*)ValueData,
                                                       sizeof(ValueData));

                    // If there exists a registered handler on the client side,for read operation, the
                    // handler should finish its operation and send the response - in such case we can
                    // just return.
                    if ( result == LE_UNAVAILABLE )
                    {
                        return;
                    }

                    BytesWritten = strlen((char*)ValueData);
                }
            }
            else
            {
                // We have received a request for a non-zero block offset before a request for a
                // block offset of 0; this is an error
                if ( resourceId != CurrentReadResId ||
                     instRef != CurrentReadInstRef)
                {
                    opErr = PA_AVC_OPERR_INTERNAL;
                    LE_ERROR("Error reading asset data.");
                }
                else
                {
                    result = LE_OK;
                }
            }

            if ( result == LE_NOT_FOUND )
                opErr = PA_AVC_OPERR_RESOURCE_UNSUPPORTED;
            else if ( result == LE_OVERFLOW )
                opErr = PA_AVC_OPERR_OVERFLOW;
            else if ( result != LE_OK )
                opErr = PA_AVC_OPERR_INTERNAL;

            if ( opErr != PA_AVC_OPERR_NO_ERROR )
            {
                pa_avc_OperationReportError(opRef, opErr);
                return;
            }

            // Send the valid response
            pa_avc_OperationReportSuccess(opRef, ValueData, BytesWritten);
            break;


        case PA_AVC_OPTYPE_WRITE:
            LE_DEBUG("PA_AVC_OPTYPE_WRITE %s/%d/%d/%d", newPrefixPtr, objId, objInstId, resourceId);

            if ( resourceId == -1 )
            {
                // Call back asset action handlers on a write to asset instance.
                result = assetData_ReadFieldListFromTLV((uint8_t*)payloadPtr,
                                                        payloadLength,
                                                        instRef,
                                                        true);
            }
            else
            {
                // The payload is a string, but can't be guaranteed that it is null terminated,
                // so copy to local buffer and null terminate it.  The payload length has already
                // been checked, so we know it will fit in the buffer.
                memcpy(ValueData, payloadPtr, payloadLength);
                ValueData[payloadLength] = 0;

                result = assetData_server_SetValue(instRef, resourceId, (const char*)ValueData);
            }

            if ( result == LE_NOT_FOUND )
                opErr = PA_AVC_OPERR_RESOURCE_UNSUPPORTED;
            else if ( result != LE_OK )
                opErr = PA_AVC_OPERR_INTERNAL;

            if ( opErr != PA_AVC_OPERR_NO_ERROR )
            {
                pa_avc_OperationReportError(opRef, opErr);
                return;
            }

            // Send the valid response
            pa_avc_OperationReportSuccess(opRef, NULL, 0);
            break;


        case PA_AVC_OPTYPE_EXECUTE:
            LE_DEBUG("PA_AVC_OPTYPE_EXEC %s/%d/%d/%d", newPrefixPtr, objId, objInstId, resourceId);

            // Execute must be on a specific resource

            result = assetData_server_Execute(instRef, resourceId);
            if ( result == LE_NOT_FOUND )
                opErr = PA_AVC_OPERR_RESOURCE_UNSUPPORTED;
            else if ( result != LE_OK )
                opErr = PA_AVC_OPERR_INTERNAL;

            if ( opErr != PA_AVC_OPERR_NO_ERROR )
            {
                pa_avc_OperationReportError(opRef, opErr);
                return;
            }

            // Send the valid response
            pa_avc_OperationReportSuccess(opRef, NULL, 0);
            break;


        case PA_AVC_OPTYPE_CREATE:
            LE_DEBUG("PA_AVC_OPTYPE_CREATE %s/%d/%d", newPrefixPtr, objId, objInstId);

            // Create is only supported on object "/lwm2m/9".
            if ( (strcmp(newPrefixPtr, "lwm2m") != 0) || (objId != 9) )
            {
                pa_avc_OperationReportError(opRef, PA_AVC_OPERR_OP_UNSUPPORTED);
                return;
            }

            // For now, assume instanceId is always generated.
            result = assetData_CreateInstanceById(newPrefixPtr, objId, -1, &instRef);
            if ( result != LE_OK )
            {
                pa_avc_OperationReportError(opRef, PA_AVC_OPERR_INTERNAL);
                return;
            }

            result = assetData_GetInstanceId(instRef, &instId);
            if ( result != LE_OK )
            {
                pa_avc_OperationReportError(opRef, PA_AVC_OPERR_INTERNAL);
                return;
            }

            // Fill in the new object instance with the received TLV in the payload
            result = assetData_ReadFieldListFromTLV((uint8_t*)payloadPtr, payloadLength, instRef, true);

            // Send the valid response
            FormatString((char*)ValueData, sizeof(ValueData), "%i", instId);

            pa_avc_OperationReportSuccess(opRef, ValueData, strlen((char*)ValueData));
            break;


        case PA_AVC_OPTYPE_DELETE:
            LE_DEBUG("PA_AVC_OPTYPE_DELETE %s/%d/%d", newPrefixPtr, objId, objInstId);

            assetData_DeleteInstance(instRef);
            pa_avc_OperationReportSuccess(opRef, NULL, 0);

            // Send registration update after the instance is removed.
            assetData_RegistrationUpdate(ASSET_DATA_SESSION_STATUS_CHECK);

            break;

        case PA_AVC_OPTYPE_OBSERVE:
            LE_DEBUG("PA_AVC_OPTYPE_OBSERVE %s/%d/%d", newPrefixPtr, objId, objInstId);

            // Observe not supported on object "/lwm2m/9".
            if ( (strcmp(newPrefixPtr, "lwm2m") == 0) && (objId == 9) )
            {
                LE_DEBUG("Observe not supported on %s/%d/%d", newPrefixPtr, objId, objInstId);
                pa_avc_OperationReportError(opRef, PA_AVC_OPERR_OP_UNSUPPORTED);
                return;
            }

            result = assetData_SetObserve(instRef, true, (uint8_t*)tokenPtr, tokenLength);

            if ( result == LE_NOT_FOUND )
                opErr = PA_AVC_OPERR_RESOURCE_UNSUPPORTED;
            else if ( result != LE_OK )
                opErr = PA_AVC_OPERR_INTERNAL;

            if ( opErr != PA_AVC_OPERR_NO_ERROR )
            {
                pa_avc_OperationReportError(opRef, opErr);
                return;
            }

            pa_avc_OperationReportSuccess(opRef, NULL, 0);
            break;

        // Observe cancel and reset are handled in the same way. i.e, stop sending notifications.
        case PA_AVC_OPTYPE_OBSERVE_CANCEL:
        case PA_AVC_OPTYPE_OBSERVE_RESET:
            LE_DEBUG("PA_AVC_OPTYPE_OBSERVE_CANCEL %s/%d/%d", newPrefixPtr, objId, objInstId);

            result = assetData_SetObserve(instRef, false, NULL, 0);

            if ( result == LE_NOT_FOUND )
                opErr = PA_AVC_OPERR_RESOURCE_UNSUPPORTED;
            else if ( result != LE_OK )
                opErr = PA_AVC_OPERR_INTERNAL;

            if ( opErr != PA_AVC_OPERR_NO_ERROR )
            {
                pa_avc_OperationReportError(opRef, opErr);
                return;
            }

            pa_avc_OperationReportSuccess(opRef, NULL, 0);
            break;

        default:
            LE_ERROR("OpType %i not currently supported", opType);
    }
}
Пример #2
0
//--------------------------------------------------------------------------------------------------
static void OperationHandler
(
    pa_avc_LWM2MOperationDataRef_t opRef

)
{
    pa_avc_OpType_t opType;
    const char* objPrefixPtr;
    int objId;
    int objInstId;
    int resourceId;
    const uint8_t* payloadPtr;
    size_t payloadLength;

    // Get the operation details from the opRef
    opType = pa_avc_GetOpType(opRef);
    pa_avc_GetOpAddress(opRef, &objPrefixPtr, &objId, &objInstId, &resourceId);
    pa_avc_GetOpPayload(opRef, &payloadPtr, &payloadLength);

    le_result_t result;
    assetData_InstanceDataRef_t instRef;
    int instId;
    uint8_t valueData[256+1];  // +1 for null byte, if storing a string
    size_t bytesWritten;
    pa_avc_OpErr_t opErr = PA_AVC_OPERR_NO_ERROR;

    // In some cases, we need to adjust the prefix string.
    const char* newPrefixPtr = objPrefixPtr;

    // Empty object prefix string should use 'lwm2m' when accessing assetData.
    // TODO: This is a work-around because the modem currently does not handle the 'lwm2m' prefix.
    if ( strlen(objPrefixPtr) == 0 )
    {
        newPrefixPtr = "lwm2m";
        LE_INFO("Defaulting to lwm2m namespace for assetData");
    }
    // Apps will have an "le_" prefix, which needs to be stripped, because the "le_" is not part
    // of the app name that is stored in assetData.
    // TODO: Should the "le_" prefix instead be added to the app name in assetData?
    else if ( strncmp(objPrefixPtr, "le_", 3) == 0 )
    {
        newPrefixPtr = objPrefixPtr+3;
        LE_DEBUG("Adjusting %s to %s", objPrefixPtr, newPrefixPtr);
    }

    LE_DEBUG("Operation: %s/%d/%d/%d <%d>", newPrefixPtr, objId, objInstId, resourceId, opType);

    // Special handling for READ if object instance is not specified (-1)
    // TODO: restructure
    if ( (opType == PA_AVC_OPTYPE_READ) && (objInstId == -1) )
    {
        LE_DEBUG("PA_AVC_OPTYPE_READ %s/%d", newPrefixPtr, objId);

        assetData_AssetDataRef_t assetRef;

        result = assetData_GetAssetRefById(newPrefixPtr, objId, &assetRef);
        if ( result == LE_NOT_FOUND )
            opErr = PA_AVC_OPERR_OBJ_UNSUPPORTED;
        else if ( result != LE_OK )
            opErr = PA_AVC_OPERR_INTERNAL;

        if ( opErr != PA_AVC_OPERR_NO_ERROR )
        {
            pa_avc_OperationReportError(opRef, opErr);
            return;
        }

        result = assetData_WriteObjectToTLV(assetRef,
                                            resourceId,
                                            valueData,
                                            sizeof(valueData),
                                            &bytesWritten);

        if ( result == LE_OVERFLOW )
            opErr = PA_AVC_OPERR_OBJ_INST_UNAVAIL;
        else if ( result != LE_OK )
            opErr = PA_AVC_OPERR_INTERNAL;

        if ( opErr != PA_AVC_OPERR_NO_ERROR )
        {
            pa_avc_OperationReportError(opRef, opErr);
        }
        else
        {
            // Send the valid response
            pa_avc_OperationReportSuccess(opRef, valueData, bytesWritten);
        }

        // TODO: Refactor so I don't need a return here.
        return;
    }


    // These operations all need a valid instanceRef.  Ensure that the specified instance exists,
    // and get the instanceRef; this check is common across several of the opTypes.
    if ( (opType == PA_AVC_OPTYPE_READ) ||
         (opType == PA_AVC_OPTYPE_WRITE) ||
         (opType == PA_AVC_OPTYPE_EXECUTE) ||
         (opType == PA_AVC_OPTYPE_DELETE) )
    {
        result = assetData_GetInstanceRefById(newPrefixPtr, objId, objInstId, &instRef);
        if ( result == LE_NOT_FOUND )
            opErr = PA_AVC_OPERR_OBJ_INST_UNAVAIL;
        else if ( result != LE_OK )
            opErr = PA_AVC_OPERR_INTERNAL;

        if ( opErr != PA_AVC_OPERR_NO_ERROR )
        {
            pa_avc_OperationReportError(opRef, opErr);
            return;
        }
    }

    switch ( opType )
    {
        case PA_AVC_OPTYPE_READ:
            LE_DEBUG("PA_AVC_OPTYPE_READ %s/%d/%d/%d", newPrefixPtr, objId, objInstId, resourceId);

            if ( resourceId == -1 )
            {
                result = assetData_WriteFieldListToTLV(instRef,
                                                       valueData,
                                                       sizeof(valueData),
                                                       &bytesWritten);

            }
            else
            {
                result = assetData_server_GetValue(instRef,
                                                   resourceId,
                                                   (char*)valueData,
                                                   sizeof(valueData));
                bytesWritten = strlen((char*)valueData);
            }

            if ( result == LE_NOT_FOUND )
                opErr = PA_AVC_OPERR_RESOURCE_UNSUPPORTED;
            else if ( result == LE_OVERFLOW )
                opErr = PA_AVC_OPERR_OBJ_INST_UNAVAIL;
            else if ( result != LE_OK )
                opErr = PA_AVC_OPERR_INTERNAL;

            if ( opErr != PA_AVC_OPERR_NO_ERROR )
            {
                pa_avc_OperationReportError(opRef, opErr);
                return;
            }

            // Send the valid response
            pa_avc_OperationReportSuccess(opRef, valueData, bytesWritten);
            break;


        case PA_AVC_OPTYPE_WRITE:
            LE_DEBUG("PA_AVC_OPTYPE_WRITE %s/%d/%d/%d", newPrefixPtr, objId, objInstId, resourceId);

            if ( resourceId == -1 )
            {
                result = assetData_ReadFieldListFromTLV((uint8_t*)payloadPtr, payloadLength, instRef);
            }
            else
            {
                // The payload is a string, but can't be guaranteed that it is null terminated,
                // so copy to local buffer and null terminate it.  The payload length has already
                // been checked, so we know it will fit in the buffer.
                memcpy(valueData, payloadPtr, payloadLength);
                valueData[payloadLength] = 0;

                result = assetData_server_SetValue(instRef, resourceId, (const char*)valueData);
            }

            if ( result == LE_NOT_FOUND )
                opErr = PA_AVC_OPERR_RESOURCE_UNSUPPORTED;
            else if ( result != LE_OK )
                opErr = PA_AVC_OPERR_INTERNAL;

            if ( opErr != PA_AVC_OPERR_NO_ERROR )
            {
                pa_avc_OperationReportError(opRef, opErr);
                return;
            }

            // Send the valid response
            pa_avc_OperationReportSuccess(opRef, NULL, 0);
            break;


        case PA_AVC_OPTYPE_EXECUTE:
            LE_DEBUG("PA_AVC_OPTYPE_EXEC %s/%d/%d/%d", newPrefixPtr, objId, objInstId, resourceId);

            // Execute must be on a specific resource

            result = assetData_server_Execute(instRef, resourceId);
            if ( result == LE_NOT_FOUND )
                opErr = PA_AVC_OPERR_RESOURCE_UNSUPPORTED;
            else if ( result != LE_OK )
                opErr = PA_AVC_OPERR_INTERNAL;

            if ( opErr != PA_AVC_OPERR_NO_ERROR )
            {
                pa_avc_OperationReportError(opRef, opErr);
                return;
            }

            // Send the valid response
            pa_avc_OperationReportSuccess(opRef, NULL, 0);
            break;


        case PA_AVC_OPTYPE_CREATE:
            LE_DEBUG("PA_AVC_OPTYPE_CREATE %s/%d/%d", newPrefixPtr, objId, objInstId);

            // Create is only supported on object "/lwm2m/9".
            if ( (strcmp(newPrefixPtr, "lwm2m") != 0) || (objId != 9) )
            {
                pa_avc_OperationReportError(opRef, PA_AVC_OPERR_OP_UNSUPPORTED);
                return;
            }

            // For now, assume instanceId is always generated.
            result = assetData_CreateInstanceById(newPrefixPtr, objId, -1, &instRef);
            if ( result != LE_OK )
            {
                pa_avc_OperationReportError(opRef, PA_AVC_OPERR_INTERNAL);
                return;
            }

            result = assetData_GetInstanceId(instRef, &instId);
            if ( result != LE_OK )
            {
                pa_avc_OperationReportError(opRef, PA_AVC_OPERR_INTERNAL);
                return;
            }

            // Fill in the new object instance with the received TLV in the payload
            result = assetData_ReadFieldListFromTLV((uint8_t*)payloadPtr, payloadLength, instRef);

            // Send the valid response
            FormatString((char*)valueData, sizeof(valueData), "%i", instId);

            pa_avc_OperationReportSuccess(opRef, valueData, strlen((char*)valueData));
            break;


        case PA_AVC_OPTYPE_DELETE:
            LE_DEBUG("PA_AVC_OPTYPE_DELETE %s/%d/%d", newPrefixPtr, objId, objInstId);

            assetData_DeleteInstance(instRef);
            pa_avc_OperationReportSuccess(opRef, NULL, 0);
            break;

        default:
            LE_ERROR("OpType %i not currently supported", opType);
    }
}