예제 #1
0
//--------------------------------------------------------------------------------------------------
static void PopulateAppInfoObjects
(
    void
)
//--------------------------------------------------------------------------------------------------
{
    appCfg_Iter_t appIterRef = appCfg_CreateAppsIter();
    char appName[MAX_APP_NAME_BYTES] = "";
    char versionBuffer[MAX_VERSION_STR_BYTES] = "";
    le_result_t result;

    int foundAppCount = 0;

    result = appCfg_GetNextItem(appIterRef);

    while (result == LE_OK)
    {
        result = appCfg_GetAppName(appIterRef, appName, sizeof(appName));

        if ((result == LE_OK) &&
            (false == IsHiddenApp(appName)))
        {
            LE_DEBUG("Loading object instance for app, '%s'.", appName);

            assetData_InstanceDataRef_t instanceRef = GetObject9InstanceForApp(appName, false);

            if (appCfg_GetVersion(appIterRef, versionBuffer, sizeof(versionBuffer)) == LE_OVERFLOW)
            {
                LE_WARN("Warning, app, '%s' version string truncated to '%s'.",
                        appName,
                        versionBuffer);
            }

            if (0 == strlen(versionBuffer))
            {
                // Use the application hash if the version is empty
                le_appInfo_GetHash(appName, versionBuffer, sizeof(versionBuffer));
            }

            assetData_client_SetString(instanceRef, O9F_PKG_VERSION, versionBuffer);

            assetData_client_SetBool(instanceRef,   O9F_UPDATE_SUPPORTED_OBJECTS, false);

            // No need to save the status in config tree, while populating object9
            SetObj9State(instanceRef, US_INSTALLED, UR_INSTALLED, false);

            foundAppCount++;
        }
        else
        {
            LE_WARN("Application name too large or is hidden, '%s.'", appName);
        }

        result = appCfg_GetNextItem(appIterRef);
    }

    appCfg_DeleteIter(appIterRef);
    LE_FATAL_IF(result != LE_NOT_FOUND,
                "Application cache initialization, unexpected error returned, (%d): \"%s\"",
                result,
                LE_RESULT_TXT(result));

    int index = 0;

    LE_DEBUG("Found app count %d.", foundAppCount);

    while (foundAppCount > 0)
    {
        assetData_InstanceDataRef_t instanceRef = NULL;
        le_result_t result = assetData_GetInstanceRefById(LWM2M_NAME, 9, index, &instanceRef);

        LE_DEBUG("Index %d.", index);

        if (result == LE_OK)
        {
            assetData_client_GetString(instanceRef, O9F_PKG_NAME, appName, sizeof(appName));

            LE_DEBUG("Mapping app '%s'.", appName);

            SetObject9InstanceForApp(appName, instanceRef);
            foundAppCount--;
        }

        index++;
    }
}
예제 #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;
    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);
    }
}
예제 #3
0
//--------------------------------------------------------------------------------------------------
static assetData_InstanceDataRef_t GetObject9InstanceForApp
(
    const char* appName,  ///< Name of the application in question.
    bool mapIfNotFound    ///< If an instance was created, should a mapping be created for it?
)
//--------------------------------------------------------------------------------------------------
{
    LE_DEBUG("Getting object 9 instance for application '%s'.", appName);

    // Attempt to read the mapping from the configuration.
    assetData_InstanceDataRef_t instanceRef = NULL;
    le_cfg_IteratorRef_t iterRef = le_cfg_CreateReadTxn(CFG_OBJECT_INFO_PATH);

    le_cfg_GoToNode(iterRef, appName);
    int instanceId = le_cfg_GetInt(iterRef, "oiid", -1);
    le_cfg_CancelTxn(iterRef);

    if (instanceId != -1)
    {
        LE_DEBUG("Was mapped to instance, %d.", instanceId);

        // Looks like there was a mapping.  Try to get that instance and make sure it's not taken
        // by another application.  If the instance was taken by another application, remap this
        // application to a new instance and update the mapping.
        if (LE_OK == assetData_GetInstanceRefById(LWM2M_NAME,
                                                  LWM2M_SOFTWARE_UPDATE,
                                                  instanceId,
                                                  &instanceRef))
        {
            char newName[MAX_APP_NAME_BYTES] = "";
            LE_ASSERT(assetData_client_GetString(instanceRef,
                                                 O9F_PKG_NAME,
                                                 newName,
                                                 sizeof(newName)) == LE_OK);

            if (strcmp(newName, appName) != 0)
            {
                LE_DEBUG("Instance has been taken by '%s', creating new.", newName);

                LE_ASSERT(assetData_CreateInstanceById(LWM2M_NAME, 9, -1, &instanceRef) == LE_OK);
                LE_ASSERT(assetData_client_SetString(instanceRef, O9F_PKG_NAME, appName) == LE_OK);

                if (mapIfNotFound)
                {
                    LE_DEBUG("Recording new instance id.");
                    SetObject9InstanceForApp(appName, instanceRef);
                }
            }
            else
            {
                LE_DEBUG("Instance is existing and has been reused.");
            }
        }
        else
        {
            LE_DEBUG("No instance found, creating new as mapped.");

            LE_ASSERT(assetData_CreateInstanceById(LWM2M_NAME,
                                                   9,
                                                   instanceId,
                                                   &instanceRef) == LE_OK);

            LE_ASSERT(assetData_client_SetString(instanceRef, O9F_PKG_NAME, appName) == LE_OK);
        }
    }
    else
    {
        LE_DEBUG("No instance mapping found, creating new.");

        // A mapping was not found.  So create a new object, and let the data store assign an
        // instance Id.  If desired, at this point record the instance mapping for later use.
        LE_ASSERT(assetData_CreateInstanceById(LWM2M_NAME, 9, -1, &instanceRef) == LE_OK);
        LE_ASSERT(assetData_client_SetString(instanceRef, O9F_PKG_NAME, appName) == LE_OK);

        if (mapIfNotFound)
        {
            LE_DEBUG("Recording new instance id.");
            SetObject9InstanceForApp(appName, instanceRef);
        }
    }

    return instanceRef;
}
예제 #4
0
파일: lwm2m.c 프로젝트: H-H-bin/legato-af
//--------------------------------------------------------------------------------------------------
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);
    }
}