/*
 * Copyright (c) 2017, Arm Limited and affiliates.
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "nsconfig.h"
#include "ns_types.h"
#include "string.h"
#include "common_functions.h"
#include "Security/PANA/pana_avp.h"
#ifdef PANA

uint8_t *pana_avp_base_write(uint8_t avp_type, uint16_t length, uint8_t *dptr, uint16_t flags, uint32_t vendor_id)
{
    dptr = common_write_16_bit(avp_type, dptr); //AVP Type
    dptr = common_write_16_bit(flags, dptr); //FLAGS
    dptr = common_write_16_bit(length, dptr); //LEN
    dptr = common_write_16_bit(0, dptr); //RESERVED
    if (flags & PANA_EAP_VENDOR_FLAG) {
        dptr = common_write_32_bit(vendor_id, dptr); //SET VENDOR
    }
    return dptr;
}

uint8_t *pana_avp_32_bit_write(uint8_t avp_type, uint32_t value, uint8_t *dptr)
{
    dptr = pana_avp_base_write(avp_type, 4, dptr, 0, 0);
    return common_write_32_bit(value, dptr);
}


uint8_t *pana_avp_write_n_bytes(uint16_t avp_type, uint16_t length, const uint8_t *value, uint8_t *dptr)
{
    dptr = pana_avp_base_write(avp_type, length,dptr, 0, 0);
    if (value) {
        memcpy(dptr, value, length);
    } else {
        memset(dptr, 0, length);
    }
    dptr += length;
    //Padding
    while(length % 4) {
        *dptr++= 0;
        length++;
    }
    return  dptr;
}

uint8_t *pana_avp_vendor_id_write_n_bytes(uint16_t avp_type, uint16_t length, const uint8_t *value, uint8_t *dptr, uint32_t vendor_id)
{
    dptr = pana_avp_base_write(avp_type, length,dptr, PANA_EAP_VENDOR_FLAG, vendor_id);
    if (value) {
        memcpy(dptr, value, length);
    } else {
        memset(dptr, 0, length);
    }
    dptr += length;

    while(length % 4) {
        *dptr++= 0;
        length++;
    }
    return  dptr;

}

bool pana_avp_discover(uint8_t *dptr, uint16_t data_len, pana_avp_t *avp)
{
    uint16_t avp_code;
    uint16_t readed = 0, pana_temp_var_16 = 0;
    avp->avp_ptr = NULL;
    while (readed  < data_len) {
        avp->flags = 0;
        avp->vendor_id = 0;
        avp_code = common_read_16_bit(dptr);
        dptr += 2;
        avp->flags = common_read_16_bit(dptr);
        dptr += 2;
        pana_temp_var_16 = common_read_16_bit(dptr);
        if (pana_temp_var_16 == 0) {
            return false;
        }
        dptr += 4; //Update pointer and Skip Reserved
        avp->len = pana_temp_var_16;

        if (avp->flags & PANA_EAP_VENDOR_FLAG) {
            avp->vendor_id = common_read_32_bit(dptr);
            dptr += 4;
            readed += 4;
        }
        readed += 8;
        readed += pana_temp_var_16;
        //Set Data Start here already
        avp->avp_ptr = dptr;
        dptr += pana_temp_var_16;

        //Check division remainder
        while(pana_temp_var_16 % 4) {
            dptr++;
            readed++;
            pana_temp_var_16++;
        }

        if (readed > data_len) {
            avp->avp_ptr = NULL;
            return false;
        }

        if (avp_code == avp->code) {
            //Save AVP pointer
            return true;
        }
        avp->avp_ptr = NULL;

    }
    return false;

}
#endif

