コード例 #1
0
static uint8_t prv_get_value(lwm2m_data_t * dataP,
                             security_instance_t * targetP)
{
    switch (dataP->id)
    {
    case LWM2M_SECURITY_URI_ID:
        lwm2m_data_encode_string(targetP->uri, dataP);
        return COAP_205_CONTENT;

    case LWM2M_SECURITY_BOOTSTRAP_ID:
        lwm2m_data_encode_bool(targetP->isBootstrap, dataP);
        return COAP_205_CONTENT;

    case LWM2M_SECURITY_SECURITY_ID:
        lwm2m_data_encode_int(targetP->securityMode, dataP);
        return COAP_205_CONTENT;

    case LWM2M_SECURITY_PUBLIC_KEY_ID:
        lwm2m_data_encode_opaque(targetP->publicIdentity, targetP->publicIdLen, dataP);
        return COAP_205_CONTENT;

    case LWM2M_SECURITY_SERVER_PUBLIC_KEY_ID:
        lwm2m_data_encode_opaque(targetP->serverPublicKey, targetP->serverPublicKeyLen, dataP);
        return COAP_205_CONTENT;

    case LWM2M_SECURITY_SECRET_KEY_ID:
        lwm2m_data_encode_opaque(targetP->secretKey, targetP->secretKeyLen, dataP);
        return COAP_205_CONTENT;

    case LWM2M_SECURITY_SMS_SECURITY_ID:
        lwm2m_data_encode_int(targetP->smsSecurityMode, dataP);
        return COAP_205_CONTENT;

    case LWM2M_SECURITY_SMS_KEY_PARAM_ID:
        lwm2m_data_encode_opaque(targetP->smsParams, targetP->smsParamsLen, dataP);
        return COAP_205_CONTENT;

    case LWM2M_SECURITY_SMS_SECRET_KEY_ID:
        lwm2m_data_encode_opaque(targetP->smsSecret, targetP->smsSecretLen, dataP);
        return COAP_205_CONTENT;

    case LWM2M_SECURITY_SMS_SERVER_NUMBER_ID:
        lwm2m_data_encode_int(0, dataP);
        return COAP_205_CONTENT;

    case LWM2M_SECURITY_SHORT_SERVER_ID:
        lwm2m_data_encode_int(targetP->shortID, dataP);
        return COAP_205_CONTENT;

    case LWM2M_SECURITY_HOLD_OFF_ID:
        lwm2m_data_encode_int(targetP->clientHoldOffTime, dataP);
        return COAP_205_CONTENT;

    default:
        return COAP_404_NOT_FOUND;
    }
}
コード例 #2
0
ファイル: object_server.c プロジェクト: alex8224/wakaama
static uint8_t prv_get_value(lwm2m_data_t * dataP,
                             server_instance_t * targetP)
{
    // There are no multiple instance resources
    dataP->type = LWM2M_TYPE_RESOURCE;

    switch (dataP->id)
    {
    case LWM2M_SERVER_SHORT_ID_ID:
        lwm2m_data_encode_int(targetP->shortServerId, dataP);
        if (0 != dataP->length) return COAP_205_CONTENT;
        else return COAP_500_INTERNAL_SERVER_ERROR;

    case LWM2M_SERVER_LIFETIME_ID:
        lwm2m_data_encode_int(targetP->lifetime, dataP);
        if (0 != dataP->length) return COAP_205_CONTENT;
        else return COAP_500_INTERNAL_SERVER_ERROR;

    case LWM2M_SERVER_MIN_PERIOD_ID:
        lwm2m_data_encode_int(targetP->minPeriod, dataP);
        if (0 != dataP->length) return COAP_205_CONTENT;
        else return COAP_500_INTERNAL_SERVER_ERROR;

    case LWM2M_SERVER_MAX_PERIOD_ID:
        lwm2m_data_encode_int(targetP->maxPeriod, dataP);
        if (0 != dataP->length) return COAP_205_CONTENT;
        else return COAP_500_INTERNAL_SERVER_ERROR;

    case LWM2M_SERVER_DISABLE_ID:
        return COAP_405_METHOD_NOT_ALLOWED;

    case LWM2M_SERVER_STORING_ID:
        lwm2m_data_encode_bool(targetP->storing, dataP);
        if (0 != dataP->length) return COAP_205_CONTENT;
        else return COAP_500_INTERNAL_SERVER_ERROR;

    case LWM2M_SERVER_BINDING_ID:
        dataP->value = (uint8_t*)targetP->binding;
        dataP->length = strlen(targetP->binding);
        dataP->flags = LWM2M_TLV_FLAG_STATIC_DATA;
        dataP->dataType = LWM2M_TYPE_STRING;
        return COAP_205_CONTENT;

    case LWM2M_SERVER_UPDATE_ID:
        return COAP_405_METHOD_NOT_ALLOWED;

    default:
        return COAP_404_NOT_FOUND;
    }
}
コード例 #3
0
ファイル: json.c プロジェクト: alex8224/wakaama
static int prv_convertRecord(_record_t * recordArray,
                             int count,
                             lwm2m_data_t ** dataP)
{
    int index;
    int tlvIndex;
    lwm2m_data_t * tlvP;

    // may be overkill
    tlvP = lwm2m_data_new(count);
    if (NULL == tlvP) return -1;
    tlvIndex = 0;

    for (index = 0 ; index < count ; index++)
    {
        lwm2m_data_t * targetP;

        if (recordArray[index].resInstId == LWM2M_MAX_ID)
        {
            targetP = tlvP + tlvIndex;
            targetP->type = LWM2M_TYPE_RESOURCE;
            targetP->id = recordArray[index].resId;
            tlvIndex++;
        }
        else
        {
            int resIndex;

            resIndex = 0;
            while (resIndex < tlvIndex
                && tlvP[resIndex].id != recordArray[index].resId)
            {
                resIndex++;
            }
            if (resIndex == tlvIndex)
            {
                targetP = lwm2m_data_new(1);
                if (NULL == targetP) goto error;

                tlvP[resIndex].type = LWM2M_TYPE_MULTIPLE_RESOURCE;
                tlvP[resIndex].id = recordArray[index].resId;
                tlvP[resIndex].length = 1;
                tlvP[resIndex].value = (uint8_t *)targetP;

                tlvIndex++;
            }
            else
            {
                targetP = lwm2m_data_new(tlvP[resIndex].length + 1);
                if (NULL == targetP) goto error;

                memcpy(targetP + 1, tlvP[resIndex].value, tlvP[resIndex].length * sizeof(lwm2m_data_t));
                lwm2m_free(tlvP[resIndex].value);   // do not use lwm2m_data_free() to preserve value pointers
                tlvP[resIndex].value = (uint8_t *)targetP;
                tlvP[resIndex].length++;
            }

            targetP->type = LWM2M_TYPE_RESOURCE_INSTANCE;
            targetP->id = recordArray[index].resInstId;
        }
        switch (recordArray[index].type)
        {
        case _TYPE_FALSE:
            lwm2m_data_encode_bool(false, targetP);
            break;
        case _TYPE_TRUE:
            lwm2m_data_encode_bool(true, targetP);
            break;
        case _TYPE_FLOAT:
        {
            size_t i;

            i = 0;
            while (i < recordArray[index].valueLen
                && recordArray[index].value[i] != '.')
            {
                i++;
            }
            if (i == recordArray[index].valueLen)
            {
                int64_t value;

                if ( 1 != lwm2m_PlainTextToInt64(recordArray[index].value,
                                                 recordArray[index].valueLen,
                                                 &value))
                {
                    goto error;
                }

                lwm2m_data_encode_int(value, targetP);
            }
            else
            {
                double value;

                if ( 1 != lwm2m_PlainTextToFloat64(recordArray[index].value,
                                                   recordArray[index].valueLen,
                                                   &value))
                {
                    goto error;
                }

                lwm2m_data_encode_float(value, targetP);
            }
        }
        break;

            // TODO: Copy string instead of pointing to it
        case _TYPE_STRING:
            targetP->flags = LWM2M_TLV_FLAG_STATIC_DATA | LWM2M_TLV_FLAG_TEXT_FORMAT;
            targetP->dataType = LWM2M_TYPE_STRING;      // or opaque ?
            targetP->length = recordArray[index].valueLen;
            targetP->value = recordArray[index].value;
            break;

        case _TYPE_UNSET:
        default:
            goto error;
        }
    }

    *dataP = tlvP;
    return tlvIndex;

error:
    lwm2m_data_free(count, tlvP);
    return -1;
}
コード例 #4
0
static int prv_add_server(bs_info_t * infoP,
                          read_server_t * dataP)
{
    lwm2m_data_t * tlvP;
    int size;
    bs_server_tlv_t * serverP;
    lwm2m_media_type_t format;

    switch (dataP->securityMode)
    {
    case LWM2M_SECURITY_MODE_NONE:
        size = 4;
        break;
    case LWM2M_SECURITY_MODE_PRE_SHARED_KEY:
        size = 6;
        break;
    case LWM2M_SECURITY_MODE_RAW_PUBLIC_KEY:
    case LWM2M_SECURITY_MODE_CERTIFICATE:
        size = 7;
        break;
    default:
        return -1;
    }

    serverP = (bs_server_tlv_t *)lwm2m_malloc(sizeof(bs_server_tlv_t));
    if (serverP == NULL) return -1;
    memset(serverP, 0, sizeof(bs_server_tlv_t));

    serverP->id = dataP->id;

    tlvP = lwm2m_data_new(size);
    if (tlvP == NULL) goto error;

    // LWM2M Server URI
    tlvP[0].id = LWM2M_SECURITY_URI_ID;
    lwm2m_data_encode_string(dataP->uri, tlvP);

    // Bootstrap Server
    tlvP[1].id = LWM2M_SECURITY_BOOTSTRAP_ID;
    lwm2m_data_encode_bool(dataP->isBootstrap, tlvP + 1);

    // Short Server ID
    tlvP[2].id = LWM2M_SECURITY_SHORT_SERVER_ID;
    lwm2m_data_encode_int(dataP->id, tlvP + 2);

    // Security Mode
    tlvP[3].id = LWM2M_SECURITY_SECURITY_ID;
    lwm2m_data_encode_int(dataP->securityMode, tlvP + 3);

    if (size > 4)
    {
        tlvP[4].id = LWM2M_SECURITY_PUBLIC_KEY_ID;
        lwm2m_data_encode_opaque(dataP->publicKey, dataP->publicKeyLen, tlvP + 4);

        tlvP[5].id = LWM2M_SECURITY_SECRET_KEY_ID;
        lwm2m_data_encode_opaque(dataP->secretKey, dataP->secretKeyLen, tlvP + 5);

        if (size == 7)
        {
            tlvP[6].id = LWM2M_SECURITY_SERVER_PUBLIC_KEY_ID;
            lwm2m_data_encode_opaque(dataP->serverKey, dataP->serverKeyLen, tlvP + 5);
        }
    }

    format = LWM2M_CONTENT_TLV;
    serverP->securityLen = lwm2m_data_serialize(NULL, size, tlvP, &format, &(serverP->securityData));
    if (serverP->securityLen <= 0) goto error;
    lwm2m_data_free(size, tlvP);

    if (dataP->isBootstrap == false)
    {
        size = 4;
        tlvP = lwm2m_data_new(size);
        if (tlvP == NULL) goto error;

        // Short Server ID
        tlvP[0].id = LWM2M_SERVER_SHORT_ID_ID;
        lwm2m_data_encode_int(dataP->id, tlvP);

        // Lifetime
        tlvP[1].id = LWM2M_SERVER_LIFETIME_ID;
        lwm2m_data_encode_int(dataP->lifetime, tlvP + 1);

        // Notification Storing
        tlvP[2].id = LWM2M_SERVER_STORING_ID;
        lwm2m_data_encode_bool(false, tlvP + 2);

        // Binding
        tlvP[3].id = LWM2M_SERVER_BINDING_ID;
        lwm2m_data_encode_string("U", tlvP + 3);

        serverP->serverLen = lwm2m_data_serialize(NULL, size, tlvP, &format, &(serverP->serverData));
        if (serverP->serverLen <= 0) goto error;
        lwm2m_data_free(size, tlvP);
    }

    infoP->serverList = (bs_server_tlv_t *)LWM2M_LIST_ADD(infoP->serverList, serverP);

    return 0;

error:
    if (tlvP != NULL) lwm2m_data_free(size, tlvP);
    if (serverP->securityData != NULL) lwm2m_free(serverP->securityData);
    if (serverP->serverData != NULL) lwm2m_free(serverP->serverData);
    lwm2m_free(serverP);

    return -1;
}
コード例 #5
0
ファイル: object_server.c プロジェクト: eclipse/wakaama
static uint8_t prv_get_value(lwm2m_data_t * dataP,
                             server_instance_t * targetP)
{
    switch (dataP->id)
    {
    case LWM2M_SERVER_SHORT_ID_ID:
        lwm2m_data_encode_int(targetP->shortServerId, dataP);
        return COAP_205_CONTENT;

    case LWM2M_SERVER_LIFETIME_ID:
        lwm2m_data_encode_int(targetP->lifetime, dataP);
        return COAP_205_CONTENT;

    case LWM2M_SERVER_MIN_PERIOD_ID:
        lwm2m_data_encode_int(targetP->defaultMinPeriod, dataP);
        return COAP_205_CONTENT;

    case LWM2M_SERVER_MAX_PERIOD_ID:
        lwm2m_data_encode_int(targetP->defaultMaxPeriod, dataP);
        return COAP_205_CONTENT;

    case LWM2M_SERVER_DISABLE_ID:
        return COAP_405_METHOD_NOT_ALLOWED;

    case LWM2M_SERVER_TIMEOUT_ID:
        lwm2m_data_encode_int(targetP->disableTimeout, dataP);
        return COAP_205_CONTENT;

    case LWM2M_SERVER_STORING_ID:
        lwm2m_data_encode_bool(targetP->storing, dataP);
        return COAP_205_CONTENT;

    case LWM2M_SERVER_BINDING_ID:
        lwm2m_data_encode_string(targetP->binding, dataP);
        return COAP_205_CONTENT;

    case LWM2M_SERVER_UPDATE_ID:
        return COAP_405_METHOD_NOT_ALLOWED;

#ifndef LWM2M_VERSION_1_0
    case LWM2M_SERVER_REG_ORDER_ID:
        if (targetP->registrationPriorityOrder >= 0)
        {
            lwm2m_data_encode_uint(targetP->registrationPriorityOrder, dataP);
            return COAP_205_CONTENT;
        }
        else
        {
            return COAP_404_NOT_FOUND;
        }

    case LWM2M_SERVER_INITIAL_REG_DELAY_ID:
        if (targetP->initialRegistrationDelayTimer >= 0)
        {
            lwm2m_data_encode_uint(targetP->initialRegistrationDelayTimer, dataP);
            return COAP_205_CONTENT;
        }
        else
        {
            return COAP_404_NOT_FOUND;
        }

    case LWM2M_SERVER_REG_FAIL_BLOCK_ID:
        if (targetP->registrationFailureBlock >= 0)
        {
            lwm2m_data_encode_bool(targetP->registrationFailureBlock > 0, dataP);
            return COAP_205_CONTENT;
        }
        else
        {
            return COAP_404_NOT_FOUND;
        }

    case LWM2M_SERVER_REG_FAIL_BOOTSTRAP_ID:
        if (targetP->bootstrapOnRegistrationFailure >= 0)
        {
            lwm2m_data_encode_bool(targetP->bootstrapOnRegistrationFailure > 0, dataP);
            return COAP_205_CONTENT;
        }
        else
        {
            return COAP_404_NOT_FOUND;
        }

    case LWM2M_SERVER_COMM_RETRY_COUNT_ID:
        if (targetP->communicationRetryCount >= 0)
        {
            lwm2m_data_encode_uint(targetP->communicationRetryCount, dataP);
            return COAP_205_CONTENT;
        }
        else
        {
            return COAP_404_NOT_FOUND;
        }

    case LWM2M_SERVER_COMM_RETRY_TIMER_ID:
        if (targetP->communicationRetryTimer >= 0)
        {
            lwm2m_data_encode_uint(targetP->communicationRetryTimer, dataP);
            return COAP_205_CONTENT;
        }
        else
        {
            return COAP_404_NOT_FOUND;
        }

    case LWM2M_SERVER_SEQ_DELAY_TIMER_ID:
        if (targetP->communicationSequenceDelayTimer >= 0)
        {
            lwm2m_data_encode_uint(targetP->communicationSequenceDelayTimer, dataP);
            return COAP_205_CONTENT;
        }
        else
        {
            return COAP_404_NOT_FOUND;
        }

    case LWM2M_SERVER_SEQ_RETRY_COUNT_ID:
        if (targetP->communicationSequenceRetryCount >= 0)
        {
            lwm2m_data_encode_uint(targetP->communicationSequenceRetryCount, dataP);
            return COAP_205_CONTENT;
        }
        else
        {
            return COAP_404_NOT_FOUND;
        }

#endif

    default:
        return COAP_404_NOT_FOUND;
    }
}
コード例 #6
0
ファイル: json.c プロジェクト: sbernard31/wakaama
static bool prv_convertValue(_record_t * recordP,
                             lwm2m_data_t * targetP)
{
    switch (recordP->type)
    {
    case _TYPE_FALSE:
        lwm2m_data_encode_bool(false, targetP);
        break;
    case _TYPE_TRUE:
        lwm2m_data_encode_bool(true, targetP);
        break;
    case _TYPE_FLOAT:
    {
        size_t i;

        i = 0;
        while (i < recordP->valueLen
            && recordP->value[i] != '.')
        {
            i++;
        }
        if (i == recordP->valueLen)
        {
            int64_t value;

            if ( 1 != utils_textToInt(recordP->value,
                                      recordP->valueLen,
                                      &value))
            {
                return false;
            }

            lwm2m_data_encode_int(value, targetP);
        }
        else
        {
            double value;

            if ( 1 != utils_textToFloat(recordP->value,
                                        recordP->valueLen,
                                        &value))
            {
                return false;
            }

            lwm2m_data_encode_float(value, targetP);
        }
    }
    break;

    case _TYPE_STRING:
        lwm2m_data_encode_opaque(recordP->value, recordP->valueLen, targetP);
        targetP->type = LWM2M_TYPE_STRING;
        break;

    case _TYPE_UNSET:
    default:
        return false;
    }

    return true;
}
コード例 #7
0
ファイル: senml_json.c プロジェクト: eclipse/wakaama
static int prv_parseItem(const uint8_t * buffer,
                         size_t bufferLen,
                         _record_t * recordP,
                         char * baseUri,
                         time_t * baseTime,
                         lwm2m_data_t *baseValue)
{
    size_t index;
    const uint8_t *name = NULL;
    size_t nameLength = 0;
    bool timeSeen = false;
    bool bnSeen = false;
    bool btSeen = false;
    bool bvSeen = false;
    bool bverSeen = false;

    memset(recordP->ids, 0xFF, 4*sizeof(uint16_t));
    memset(&recordP->value, 0, sizeof(recordP->value));
    recordP->time = 0;

    index = 0;
    do
    {
        size_t tokenStart;
        size_t tokenLen;
        size_t valueStart;
        size_t valueLen;
        int next;

        next = json_split(buffer+index,
                          bufferLen-index,
                          &tokenStart,
                          &tokenLen,
                          &valueStart,
                          &valueLen);
        if (next < 0) return -1;
        if (tokenLen == 0) return -1;

        switch (buffer[index+tokenStart])
        {
        case 'b':
            if (tokenLen == 2 && buffer[index+tokenStart+1] == 'n')
            {
                if (bnSeen) return -1;
                bnSeen = true;
                /* Check for " around URI */
                if (valueLen < 2
                 || buffer[index+valueStart] != '"'
                 || buffer[index+valueStart+valueLen-1] != '"')
                {
                    return -1;
                }
                if (valueLen >= 3)
                {
                    if (valueLen == 3 && buffer[index+valueStart+1] != '/') return -1;
                    if (valueLen > URI_MAX_STRING_LEN) return -1;
                    memcpy(baseUri, buffer+index+valueStart+1, valueLen-2);
                    baseUri[valueLen-2] = '\0';
                }
                else
                {
                    baseUri[0] = '\0';
                }
            }
            else if (tokenLen == 2 && buffer[index+tokenStart+1] == 't')
            {
                if (btSeen) return -1;
                btSeen = true;
                if (!json_convertTime(buffer+index+valueStart, valueLen, baseTime))
                    return -1;
            }
            else if (tokenLen == 2 && buffer[index+tokenStart+1] == 'v')
            {
                if (bvSeen) return -1;
                bvSeen = true;
                if (valueLen == 0)
                {
                    baseValue->type = LWM2M_TYPE_UNDEFINED;
                }
                else
                {
                    if (!json_convertNumeric(buffer+index+valueStart, valueLen, baseValue))
                        return -1;
                    /* Convert explicit 0 to implicit 0 */
                    switch (baseValue->type)
                    {
                    case LWM2M_TYPE_INTEGER:
                        if (baseValue->value.asInteger == 0)
                        {
                            baseValue->type = LWM2M_TYPE_UNDEFINED;
                        }
                        break;
                    case LWM2M_TYPE_UNSIGNED_INTEGER:
                        if (baseValue->value.asUnsigned == 0)
                        {
                            baseValue->type = LWM2M_TYPE_UNDEFINED;
                        }
                        break;
                    case LWM2M_TYPE_FLOAT:
                        if (baseValue->value.asFloat == 0.0)
                        {
                            baseValue->type = LWM2M_TYPE_UNDEFINED;
                        }
                        break;
                    default:
                        return -1;
                    }
                }
            }
            else if (tokenLen == 4
                  && buffer[index+tokenStart+1] == 'v'
                  && buffer[index+tokenStart+2] == 'e'
                  && buffer[index+tokenStart+3] == 'r')
            {
                int64_t value;
                int res;
                if (bverSeen) return -1;
                bverSeen = true;
                res = utils_textToInt(buffer+index+valueStart, valueLen, &value);
                /* Only the default version (10) is supported */
                if (!res || value != 10)
                {
                    return -1;
                }
            }
            else if (buffer[index+tokenStart+tokenLen-1] == '_')
            {
                /* Label ending in _ must be supported or generate error. */
                return -1;
            }
            break;
        case 'n':
        {
            if (tokenLen == 1)
            {
                if (name) return -1;

                /* Check for " around URI */
                if (valueLen < 2
                        || buffer[index+valueStart] != '"'
                                || buffer[index+valueStart+valueLen-1] != '"')
                {
                    return -1;
                }
                name = buffer + index + valueStart + 1;
                nameLength = valueLen - 2;
            }
            else if (buffer[index+tokenStart+tokenLen-1] == '_')
            {
                /* Label ending in _ must be supported or generate error. */
                return -1;
            }
            break;
        }
        case 't':
            if (tokenLen == 1)
            {
                if (timeSeen) return -1;
                timeSeen = true;
                if (!json_convertTime(buffer+index+valueStart, valueLen, &recordP->time))
                    return -1;
            }
            else if (buffer[index+tokenStart+tokenLen-1] == '_')
            {
                /* Label ending in _ must be supported or generate error. */
                return -1;
            }
            break;
        case 'v':
            if (tokenLen == 1)
            {
                if (recordP->value.type != LWM2M_TYPE_UNDEFINED) return -1;
                if (!json_convertNumeric(buffer+index+valueStart, valueLen, &recordP->value))
                    return -1;
            }
            else if (tokenLen == 2 && buffer[index+tokenStart+1] == 'b')
            {
                if (recordP->value.type != LWM2M_TYPE_UNDEFINED) return -1;
                if (0 == lwm2m_strncmp(JSON_TRUE_STRING,
                                       (char *)buffer + index + valueStart,
                                       valueLen))
                {
                    lwm2m_data_encode_bool(true, &recordP->value);
                }
                else if (0 == lwm2m_strncmp(JSON_FALSE_STRING,
                                            (char *)buffer + index + valueStart,
                                            valueLen))
                {
                    lwm2m_data_encode_bool(false, &recordP->value);
                }
                else
                {
                    return -1;
                }
            }
            else if (tokenLen == 2
                  && (buffer[index+tokenStart+1] == 'd'
                   || buffer[index+tokenStart+1] == 's'))
            {
                if (recordP->value.type != LWM2M_TYPE_UNDEFINED) return -1;
                /* Check for " around value */
                if (valueLen < 2
                 || buffer[index+valueStart] != '"'
                 || buffer[index+valueStart+valueLen-1] != '"')
                {
                    return -1;
                }
                if (buffer[index+tokenStart+1] == 'd')
                {
                    /* Don't use lwm2m_data_encode_opaque here. It would copy the buffer */
                    recordP->value.type = LWM2M_TYPE_OPAQUE;
                }
                else
                {
                    /* Don't use lwm2m_data_encode_nstring here. It would copy the buffer */
                    recordP->value.type = LWM2M_TYPE_STRING;
                }
                recordP->value.value.asBuffer.buffer = (uint8_t *)buffer + index + valueStart + 1;
                recordP->value.value.asBuffer.length = valueLen - 2;
            }
            else if (tokenLen == 3 && buffer[index+tokenStart+1] == 'l' && buffer[index+tokenStart+2] == 'o')
            {
                if (recordP->value.type != LWM2M_TYPE_UNDEFINED) return -1;
                /* Check for " around value */
                if (valueLen < 2
                 || buffer[index+valueStart] != '"'
                 || buffer[index+valueStart+valueLen-1] != '"')
                {
                    return -1;
                }
                if (!utils_textToObjLink(buffer + index + valueStart + 1,
                                         valueLen - 2,
                                         &recordP->value.value.asObjLink.objectId,
                                         &recordP->value.value.asObjLink.objectInstanceId))
                {
                    return -1;
                }
                recordP->value.type = LWM2M_TYPE_OBJECT_LINK;
            }
            else if (buffer[index+tokenStart+tokenLen-1] == '_')
            {
                /* Label ending in _ must be supported or generate error. */
                return -1;
            }
            break;
        default:
            if (buffer[index+tokenStart+tokenLen-1] == '_')
            {
                /* Label ending in _ must be supported or generate error. */
                return -1;
            }
            break;
        }

        index += next + 1;
    } while (index < bufferLen);

    /* Combine with base values */
    recordP->time += *baseTime;
    if (baseUri[0] || name)
    {
        lwm2m_uri_t uri;
        size_t length = strlen(baseUri);
        char uriStr[URI_MAX_STRING_LEN];
        if (length > sizeof(uriStr)) return -1;
        memcpy(uriStr, baseUri, length);
        if (nameLength)
        {
            if (nameLength + length > sizeof(uriStr)) return -1;
            memcpy(uriStr + length, name, nameLength);
            length += nameLength;
        }
        if (!lwm2m_stringToUri(uriStr, length, &uri)) return -1;
        if (LWM2M_URI_IS_SET_OBJECT(&uri))
        {
            recordP->ids[0] = uri.objectId;
        }
        if (LWM2M_URI_IS_SET_INSTANCE(&uri))
        {
            recordP->ids[1] = uri.instanceId;
        }
        if (LWM2M_URI_IS_SET_RESOURCE(&uri))
        {
            recordP->ids[2] = uri.resourceId;
        }
        if (LWM2M_URI_IS_SET_RESOURCE_INSTANCE(&uri))
        {
            recordP->ids[3] = uri.resourceInstanceId;
        }
    }
    if (baseValue->type != LWM2M_TYPE_UNDEFINED)
    {
        if (recordP->value.type == LWM2M_TYPE_UNDEFINED)
        {
            memcpy(&recordP->value, baseValue, sizeof(*baseValue));
        }
        else
        {
            switch (recordP->value.type)
            {
            case LWM2M_TYPE_INTEGER:
                switch(baseValue->type)
                {
                case LWM2M_TYPE_INTEGER:
                    recordP->value.value.asInteger += baseValue->value.asInteger;
                    break;
                case LWM2M_TYPE_UNSIGNED_INTEGER:
                    recordP->value.value.asInteger += baseValue->value.asUnsigned;
                    break;
                case LWM2M_TYPE_FLOAT:
                    recordP->value.value.asInteger += baseValue->value.asFloat;
                    break;
                default:
                    return -1;
                }
                break;
            case LWM2M_TYPE_UNSIGNED_INTEGER:
                switch(baseValue->type)
                {
                case LWM2M_TYPE_INTEGER:
                    recordP->value.value.asUnsigned += baseValue->value.asInteger;
                    break;
                case LWM2M_TYPE_UNSIGNED_INTEGER:
                    recordP->value.value.asUnsigned += baseValue->value.asUnsigned;
                    break;
                case LWM2M_TYPE_FLOAT:
                    recordP->value.value.asUnsigned += baseValue->value.asFloat;
                    break;
                default:
                    return -1;
                }
                break;
            case LWM2M_TYPE_FLOAT:
                switch(baseValue->type)
                {
                case LWM2M_TYPE_INTEGER:
                    recordP->value.value.asFloat += baseValue->value.asInteger;
                    break;
                case LWM2M_TYPE_UNSIGNED_INTEGER:
                    recordP->value.value.asFloat += baseValue->value.asUnsigned;
                    break;
                case LWM2M_TYPE_FLOAT:
                    recordP->value.value.asFloat += baseValue->value.asFloat;
                    break;
                default:
                    return -1;
                }
                break;
            default:
                return -1;
            }
        }
    }

    return 0;
}