// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
/*
 * Copyright (c) 2021 MediaTek Inc.
 */

#include "rohc_decomp.h"
#include "rohc_decomp_internal.h"
#include "rohc_decomp_network.h"
#include "net_buf.h"

#include "atsc30_utils.h"
#include "atsc30_log.h"

//-------------------------------------------------------------------------------------------------
//  Debug Constants and Macros
//-------------------------------------------------------------------------------------------------

//-------------------------------------------------------------------------------------------------
//  Constants
//-------------------------------------------------------------------------------------------------

//-------------------------------------------------------------------------------------------------
//  Macros
//-------------------------------------------------------------------------------------------------

//-------------------------------------------------------------------------------------------------
//  Structs and Enums
//-------------------------------------------------------------------------------------------------

//-------------------------------------------------------------------------------------------------
//  Functions Prototype
//-------------------------------------------------------------------------------------------------

//-------------------------------------------------------------------------------------------------
//  Variables
//-------------------------------------------------------------------------------------------------

//-------------------------------------------------------------------------------------------------
//  Internal Functions
//-------------------------------------------------------------------------------------------------
static rohc_decomp_status_t  decode_IR_NO_D_header(
		rohc_decomp_context_t *const ctx,
		const net_buf_t IR_NO_D_pkt,
		const u8 non_cid_1st_oct,
		const rohc_non_cid_2nd_octect_index_t non_cid_2nd_oct_idx)
{
	u8 k = (u8)non_cid_2nd_oct_idx;
	u8 crc_vfy;
	u8 crc_hdr;

	/*
	 * profile(1B)+ CRC(1B)+ static(14B) = 16 Bytes
	 * non_cid_2nd_oct = (0 or 1)cid/add_cid oct + IR_packet type(1B)
	 */
	u8 tot_hdr_len = 16 + (u8)non_cid_2nd_oct_idx;
	u8 crc_vfy_copied_hdr[32];

	if (ROHC_VERIFY(
		(non_cid_2nd_oct_idx != NON_CID_SECOND_OCTECT_INDEX_1) &&
		(non_cid_2nd_oct_idx != NON_CID_SECOND_OCTECT_INDEX_2)))
		return ROHC_DECOMP_ERROR;

	if (ATSC30_NULL_PTR_CHECK(ctx))
		return ROHC_DECOMP_ERROR;

	if (!ctx->en_ip_dyn_ext_field)
		tot_hdr_len -= 1;

	if (!(ROHC_PACKET_IS_IR_PACKET(non_cid_1st_oct)
		|| ROHC_PACKET_IS_IR_NO_D_PACKET(non_cid_1st_oct))) {
		ROHC_LOG_ENHANCED_ERROR(
			"bad ir, type octect 0x%02x\n",
			non_cid_1st_oct);

		return ROHC_DECOMP_PACKER_TYPE_ERROR;
	} else if (net_buf_data_size(IR_NO_D_pkt) < tot_hdr_len) {
		ROHC_LOG_ERROR(
			"IR NO D data buffer too short (%d) bytes, need hdr len %d\n",
			net_buf_data_size(IR_NO_D_pkt),
			tot_hdr_len);

		return ROHC_DECOMP_INPUT_BUFFER_ERROR;
	} else if (net_buf_get_val(IR_NO_D_pkt, k) != (u8) ROHC_PROFILE_UDP) {
		ROHC_LOG_ERROR(
			"unsupported profile %d, only support udp/ipv4 u mode\n",
			net_buf_get_val(IR_NO_D_pkt, k));

		return ROHC_DECOMP_PROFILE_NOT_SUPPORT;
	}

	++k;
	crc_hdr = net_buf_get_val(IR_NO_D_pkt, k);

	memcpy(crc_vfy_copied_hdr, net_buf_get_ptr(IR_NO_D_pkt, 0), tot_hdr_len);
	crc_vfy_copied_hdr[k] = 0;
	crc_vfy = rohc_cal_crc(ROHC_CRC_TYPE_8, crc_vfy_copied_hdr, tot_hdr_len, CRC_8_INIT_VAL);

	if (crc_hdr != crc_vfy) {
		ROHC_LOG_WARN(
			"IR packet crc error, header crc 0x%x, cal crc 0x%x\n",
			crc_hdr,
			crc_vfy);

		return ROHC_DECOMP_BAD_CRC;
	}

	++k;
	rohc_decomp_network_decode_static_chain(&ctx->net_ctx, net_buf_get_ptr(IR_NO_D_pkt, k));

	// k += 14;
	// decode_network_dynamic(
	//		&ctx->net_ctx,
	//		net_buf_get_ptr(IR_NO_D_pkt, k),
	//		ctx->en_ip_dyn_ext_field);

	ctx->header_size = tot_hdr_len;

	ROHC_LOG_DEBUG(
		"%s Done\n",
		__func__);

	return ROHC_DECOMP_SUCCESS;
}

static rohc_decomp_status_t decode_IR_header(
		rohc_decomp_context_t *ctx,
		net_buf_t IR_pkt,
		u8 non_cid_1st_oct,
		rohc_non_cid_2nd_octect_index_t non_cid_2nd_oct_idx)
{
	u8 k = (u8)non_cid_2nd_oct_idx;
	u8 crc_vfy;
	u8 crc_hdr;

	/*
	 * profile(1B)+ CRC(1B)+ static(14B)+ dynamic(10B)(with 1 byte ip dyn ext bytes) = 26 Bytes
	 * non_cid_2nd_oct = (0 or 1)cid/add_cid oct + IR_packet type(1B)
	 */
	u8 tot_hdr_len = 26 + (u8)non_cid_2nd_oct_idx;
	u8 crc_vfy_copied_hdr[32];

	if (ROHC_VERIFY(
		(non_cid_2nd_oct_idx != NON_CID_SECOND_OCTECT_INDEX_1) &&
		(non_cid_2nd_oct_idx != NON_CID_SECOND_OCTECT_INDEX_2)))
		return ROHC_DECOMP_ERROR;

	if (ATSC30_NULL_PTR_CHECK(ctx))
		return ROHC_DECOMP_ERROR;

	if (!ctx->en_ip_dyn_ext_field)
		tot_hdr_len -= 1;

	if (!ROHC_PACKET_IS_IR_PACKET(non_cid_1st_oct)) {
		ROHC_LOG_ERROR(
			"%s bad ir, type octect 0x%02x\n",
			__func__,
			non_cid_1st_oct);

		return ROHC_DECOMP_PACKER_TYPE_ERROR;
	} else if (net_buf_data_size(IR_pkt) < tot_hdr_len) {
		ROHC_LOG_ERROR(
			"IR data buffer too short (%d) bytes, need hdr len %d\n",
			net_buf_data_size(IR_pkt),
			tot_hdr_len);

		return ROHC_DECOMP_INPUT_BUFFER_ERROR;
	} else if (net_buf_get_val(IR_pkt, k) != (u8) ROHC_PROFILE_UDP) {
		ROHC_LOG_ERROR(
			"unsupported profile %d, only support udp/ipv4 u mode\n",
			net_buf_get_val(IR_pkt, k));

		return ROHC_DECOMP_PROFILE_NOT_SUPPORT;
	}

	++k;
	crc_hdr = net_buf_get_val(IR_pkt, k);

	memcpy(crc_vfy_copied_hdr, net_buf_get_ptr(IR_pkt, 0), tot_hdr_len);
	crc_vfy_copied_hdr[k] = 0;
	crc_vfy = rohc_cal_crc(ROHC_CRC_TYPE_8, crc_vfy_copied_hdr, tot_hdr_len, CRC_8_INIT_VAL);

	if (crc_hdr != crc_vfy) {
		ROHC_LOG_WARN(
			"IR packet crc error, header crc 0x%x, cal crc 0x%x\n",
			crc_hdr,
			crc_vfy);

		return ROHC_DECOMP_BAD_CRC;
	}

	++k;
	rohc_decomp_network_decode_static_chain(
		&ctx->net_ctx,
		net_buf_get_ptr(IR_pkt, k));

	k += 14;
	rohc_decomp_network_decode_dynamic_chain(
		&ctx->net_ctx,
		net_buf_get_ptr(IR_pkt, k),
		ctx->en_ip_dyn_ext_field);

	ctx->header_size = tot_hdr_len;

	ROHC_LOG_DEBUG(
		"%s Done\n",
		__func__);

	return ROHC_DECOMP_SUCCESS;
}

/*
 *   0   1   2   3   4   5   6   7
 *  --- --- --- --- --- --- --- ---
 * :         Add-CID octet         : if for small CIDs and CID != 0
 * +---+---+---+---+---+---+---+---+
 * | 1   1   1   1   1   0   0   0 | IR-DYN packet type
 * +---+---+---+---+---+---+---+---+
 * :                               :
 * /     0-1 octets of CID info    / 0-1 octets if for large CIDs
 * :                               :
 * +---+---+---+---+---+---+---+---+
 * |            Profile            | 1 octet
 * +---+---+---+---+---+---+---+---+
 * |              CRC              | 1 octet
 * +---+---+---+---+---+---+---+---+
 * |                               |
 * /         Dynamic chain         / variable length
 * |                               |
 * +---+---+---+---+---+---+---+---+
 * |             SN                | 2 octets if not RTP nor ESP
 * +---+---+---+---+---+---+---+---+
 * :                               :
 * /           Payload             / variable length
 * :                               :
 *  - - - - - - - - - - - - - - - -
 */

static rohc_decomp_status_t decode_IR_DYN_header(
		rohc_decomp_context_t *const ctx,
		const net_buf_t IR_dyn_pkt,
		const u8 non_cid_1st_oct,
		const rohc_non_cid_2nd_octect_index_t non_cid_2nd_oct_idx)
{
	u8 k = (u8)non_cid_2nd_oct_idx;
	u8 crc_vfy;
	u8 crc_hdr;

	/* profile(1B)+ CRC(1B)+  dynamic(10B)(with 1 byte ip dyn ext bytes) = 12 Bytes
	 * non_cid_2nd_oct = (0 or 1)cid/add_cid oct + IR_packet type(1B)
	 */
	u8 tot_hdr_len = 12 + (u8)non_cid_2nd_oct_idx;
	u8 crc_vfy_copied_hdr[16];

	if (ROHC_VERIFY(
		(non_cid_2nd_oct_idx != NON_CID_SECOND_OCTECT_INDEX_1) &&
		(non_cid_2nd_oct_idx != NON_CID_SECOND_OCTECT_INDEX_2)))
		return ROHC_DECOMP_ERROR;

	if (ATSC30_NULL_PTR_CHECK(ctx))
		return ROHC_DECOMP_ERROR;

	if (!ctx->en_ip_dyn_ext_field)
		tot_hdr_len -= 1;

	if (!ROHC_PACKET_IS_IR_DYN_PACKET(non_cid_1st_oct)) {
		ROHC_LOG_ERROR(
			"%s bad ir dyn, type octect%d\n",
			__func__,
			non_cid_1st_oct);

		return ROHC_DECOMP_PACKER_TYPE_ERROR;
	}
	if (net_buf_data_size(IR_dyn_pkt) < tot_hdr_len) {
		ROHC_LOG_ERROR(
			"IR DYN data buffer too short(%d) bytes, need hdr len %d\n",
			net_buf_data_size(IR_dyn_pkt),
			tot_hdr_len);

		return ROHC_DECOMP_INPUT_BUFFER_ERROR;
	} else if (net_buf_get_val(IR_dyn_pkt, k) != (u8) ROHC_PROFILE_UDP) {
		ROHC_LOG_ERROR(
			"unsupported profile %d, only support udp/ipv4 u mode\n",
			net_buf_get_val(IR_dyn_pkt, k));

		return ROHC_DECOMP_PROFILE_NOT_SUPPORT;
	}

	++k;
	crc_hdr = net_buf_get_val(IR_dyn_pkt, k);

	memcpy(crc_vfy_copied_hdr,
			net_buf_get_ptr(IR_dyn_pkt, 0),
			tot_hdr_len);
	crc_vfy_copied_hdr[k] = 0;

	crc_vfy = rohc_cal_crc(
			ROHC_CRC_TYPE_8,
			crc_vfy_copied_hdr,
			tot_hdr_len,
			CRC_8_INIT_VAL);

	if (crc_hdr != crc_vfy) {
		ROHC_LOG_WARN(
			"CRC detect error in IR packet, crc in packet 0x%x, crc calculated 0x%x\n",
			crc_hdr,
			crc_vfy);

		return ROHC_DECOMP_BAD_CRC;
	}

	++k;
	rohc_decomp_network_decode_dynamic_chain(
		&ctx->net_ctx,
		net_buf_get_ptr(IR_dyn_pkt, k),
		ctx->en_ip_dyn_ext_field);

	ctx->header_size = tot_hdr_len;

	ROHC_LOG_DEBUG(
		"%s Done\n",
		__func__);

	return ROHC_DECOMP_SUCCESS;
}

/*
 *   0   1   2   3   4   5   6   7
 * +---+---+---+---+---+---+---+---+
 * | 1   1   0 |          SN       |
 * +===+===+===+===+===+===+===+===+
 * | X |            CRC            |   X = 0
 * +---+---+---+---+---+---+---+---+
 */
static rohc_decomp_status_t decode_UOR2_header(
		rohc_decomp_context_t *const ctx,
		const net_buf_t uor_2_pkt,
		const u8 non_cid_1st_oct,
		const rohc_non_cid_2nd_octect_index_t non_cid_2nd_oct_idx)
{
	u8 rand_field_len = 0;
	u8 SN = 0;
	u8 k = (u8)non_cid_2nd_oct_idx;
	u8 crc_hdr;

	//X_CRC 1 Byte + non_cid_2nd_oct = (0 or 1)cid/add_cid oct + SN OCT(110SN)
	u8 tot_hdr_len = 1 + (u8)non_cid_2nd_oct_idx;

	if (ROHC_VERIFY(
		(non_cid_2nd_oct_idx != NON_CID_SECOND_OCTECT_INDEX_1) &&
		(non_cid_2nd_oct_idx != NON_CID_SECOND_OCTECT_INDEX_2)))
		return false;

	if (ATSC30_NULL_PTR_CHECK(ctx))
		return false;

	if (net_buf_data_size(uor_2_pkt) < tot_hdr_len) {
		ROHC_LOG_ERROR(
			"UOR2 data buffer too short(%d) bytes, need hdr len %d\n",
			net_buf_data_size(uor_2_pkt),
			tot_hdr_len);

		return ROHC_DECOMP_INPUT_BUFFER_ERROR;
	}

	SN = 0x1F & non_cid_1st_oct; /* 1 1 0 x x x x x */
	ROHC_DECOMP_NETWORK_SET_SN(ctx->net_ctx, SN, UOR_2_SN_BITS);

	crc_hdr =  0x7F & net_buf_get_val(uor_2_pkt, k++);
	ROHC_DECOMP_NETWORK_SET_CRC(ctx->net_ctx, crc_hdr, ROHC_CRC_TYPE_7);

	rand_field_len = rohc_decomp_network_decode_UO_x_random_fields(
				&ctx->net_ctx,
				net_buf_get_ptr(uor_2_pkt, k));

	if (rand_field_len == INVALID_RANDOM_FIELD_LEN)
		return ROHC_DECOMP_ERROR;

	ctx->header_size = tot_hdr_len + rand_field_len;

	ROHC_LOG_DEBUG(
		"%s Done\n",
		__func__);

	return ROHC_DECOMP_SUCCESS;
}

/*
 *   0   1   2   3   4   5   6   7
 * +---+---+---+---+---+---+---+---+
 * | 0 |      SN       |    CRC    |
 * +===+===+===+===+===+===+===+===+
 */
static rohc_decomp_status_t decode_UO0_header(
		rohc_decomp_context_t *const ctx,
		const net_buf_t uo_0_pkt,
		const u8 non_cid_1st_oct,
		const rohc_non_cid_2nd_octect_index_t non_cid_2nd_oct_idx)
{
	u8 rand_field_len = 0;
	u8 SN = 0;
	u8 k = (u8)non_cid_2nd_oct_idx;
	u8 crc_hdr;

	u8 tot_hdr_len = (u8)non_cid_2nd_oct_idx;

	if (ROHC_VERIFY(
		(non_cid_2nd_oct_idx != NON_CID_SECOND_OCTECT_INDEX_1) &&
		(non_cid_2nd_oct_idx != NON_CID_SECOND_OCTECT_INDEX_2)))
		return false;

	if (ATSC30_NULL_PTR_CHECK(ctx))
		return false;

	if (net_buf_data_size(uo_0_pkt) < tot_hdr_len) {
		ROHC_LOG_ERROR(
			"UO-0 data buffer too short (%d) bytes, need hdr len %d\n",
			net_buf_data_size(uo_0_pkt),
			tot_hdr_len);

		return ROHC_DECOMP_INPUT_BUFFER_ERROR;
	}

	SN = (non_cid_1st_oct >> 3) & 0x0F;
	ROHC_DECOMP_NETWORK_SET_SN(ctx->net_ctx, SN, UO_0_SN_BITS);

	crc_hdr = non_cid_1st_oct & 0x7;
	ROHC_DECOMP_NETWORK_SET_CRC(ctx->net_ctx, crc_hdr, ROHC_CRC_TYPE_3);

	rand_field_len = rohc_decomp_network_decode_UO_x_random_fields(
				&ctx->net_ctx,
				net_buf_get_ptr(uo_0_pkt, k));

	if (rand_field_len == INVALID_RANDOM_FIELD_LEN)
		return ROHC_DECOMP_ERROR;

	ctx->header_size = tot_hdr_len + rand_field_len;

	ROHC_LOG_DEBUG(
		"%s Done\n",
		__func__);

	return ROHC_DECOMP_SUCCESS;
}

/*
 *   0   1   2   3   4   5   6   7
 * +---+---+---+---+---+---+---+---+
 * | 1   0 |         IP-ID         |
 * +===+===+===+===+===+===+===+===+
 * |        SN         |     CRC   |
 * +---+---+---+---+---+---+---+---+
 */

static rohc_decomp_status_t decode_UO1_header(
		rohc_decomp_context_t *const ctx,
		const net_buf_t uo_1_pkt,
		const u8 non_cid_1st_oct,
		const rohc_non_cid_2nd_octect_index_t non_cid_2nd_oct_idx)
{
	u8 rand_field_len = 0;
	u8 ip_id_ofst;
	u8 SN;
	u8 k = (u8)non_cid_2nd_oct_idx;
	u8 crc_hdr;
	u8 non_cid_2nd_oct;

	//SN_CRC 1 Byte + non_cid_2nd_oct = (0 or 1)cid/add_cid oct + SN OCT(110SN)
	u8 tot_hdr_len = 1 + (u8)non_cid_2nd_oct_idx;

	if (ROHC_VERIFY(
		(non_cid_2nd_oct_idx != NON_CID_SECOND_OCTECT_INDEX_1) &&
		(non_cid_2nd_oct_idx != NON_CID_SECOND_OCTECT_INDEX_2)))
		return false;

	if (ATSC30_NULL_PTR_CHECK(ctx))
		return false;

	if (net_buf_data_size(uo_1_pkt) < tot_hdr_len) {
		ROHC_LOG_ERROR(
			"UO-1 data buffer too short (%d) bytes, need hdr len %d\n",
			net_buf_data_size(uo_1_pkt),
			tot_hdr_len);

		return ROHC_DECOMP_INPUT_BUFFER_ERROR;
	}

	ip_id_ofst = non_cid_1st_oct & 0x3F;
	ROHC_LOG_DEBUG(
		"uo_1 decode uo_1_ip_id 0x%02x lsb val 0x%02x\n",
		non_cid_1st_oct,
		ip_id_ofst);
	ROHC_DECOMP_NETWORK_SET_IP_ID_OFFSET(
		ctx->net_ctx,
		ip_id_ofst,
		UO_1_IP_ID_BITS);

	non_cid_2nd_oct = net_buf_get_val(uo_1_pkt, k);

	SN = (non_cid_2nd_oct >> 3) & 0x1F;
	ROHC_LOG_DEBUG(
		"uo_1 decode sn_crc 0x%02x lsb val 0x%02x\n",
		non_cid_2nd_oct, SN);
	ROHC_DECOMP_NETWORK_SET_SN(ctx->net_ctx, SN, UO_1_SN_BITS);

	crc_hdr = non_cid_2nd_oct & 0x7;
	ROHC_DECOMP_NETWORK_SET_CRC(
		ctx->net_ctx,
		crc_hdr,
		ROHC_CRC_TYPE_3);

	++k;
	rand_field_len = rohc_decomp_network_decode_UO_x_random_fields(
				&ctx->net_ctx,
				net_buf_get_ptr(uo_1_pkt, k));

	if (rand_field_len == INVALID_RANDOM_FIELD_LEN)
		return ROHC_DECOMP_ERROR;

	ctx->header_size = tot_hdr_len + rand_field_len;

	ROHC_LOG_DEBUG(
		"%s Done\n",
		__func__);

	return ROHC_DECOMP_SUCCESS;

}

static rohc_decomp_status_t decode_rohc_packet_header(
		rohc_decomp_context_t *const ctx,
		const net_buf_t comp_pkt,
		const u8 non_cid_1st_oct,
		const rohc_non_cid_2nd_octect_index_t non_cid_2nd_oct_idx)
{
	if (ATSC30_NULL_PTR_CHECK(ctx))
		return false;

	switch (ctx->packet_type) {
	case ROHC_PACKET_IR:
		return decode_IR_header(
				ctx,
				comp_pkt,
				non_cid_1st_oct,
				non_cid_2nd_oct_idx);

	case ROHC_PACKET_IR_NO_D:
		return decode_IR_NO_D_header(
				ctx,
				comp_pkt,
				non_cid_1st_oct,
				non_cid_2nd_oct_idx);

	case ROHC_PACKET_IR_DYN:
		return decode_IR_DYN_header(
				ctx,
				comp_pkt,
				non_cid_1st_oct,
				non_cid_2nd_oct_idx);

	case ROHC_PACKET_UO_0:
		return decode_UO0_header(
				ctx,
				comp_pkt,
				non_cid_1st_oct,
				non_cid_2nd_oct_idx);

	case ROHC_PACKET_UO_1:
		return decode_UO1_header(
				ctx,
				comp_pkt,
				non_cid_1st_oct,
				non_cid_2nd_oct_idx);

	case ROHC_PACKET_UOR_2:
		return decode_UOR2_header(
				ctx,
				comp_pkt,
				non_cid_1st_oct,
				non_cid_2nd_oct_idx);

	default:
		ROHC_LOG_ERROR(
			"%s unknonwn packet type %d\n",
			__func__,
			ctx->packet_type);
		return false;
	}

	return true;
}

static rohc_decomp_context_t *find_decomp_context(
		rohc_decompressor_t *const decomp,
		const u8 cid)
{
#define INVALID_COMP_CTX_INDEX (0xFFFF)

	static size_t current_time_clock;

	rohc_decomp_context_management_t *mm;
	rohc_decomp_context_t *ctx = NULL;

	u16 free_idx = INVALID_COMP_CTX_INDEX;
	u16 lru_idx = INVALID_COMP_CTX_INDEX;
	size_t lru_time = current_time_clock;
	u16 i;

	if (ATSC30_NULL_PTR_CHECK(decomp))
		return NULL;
	if (ATSC30_NULL_PTR_CHECK(decomp->ctx_mm.ctx_array))
		return NULL;
	if (ATSC30_NULL_PTR_CHECK(decomp->ctx_mm.lru_record))
		return NULL;

	mm = &decomp->ctx_mm;

	current_time_clock++;

	for (i = 0; i <= mm->total_num; i++) {
		if (mm->ctx_array[i].in_use) {
			if (mm->ctx_array[i].cid == cid) {
				ctx = &mm->ctx_array[i];
				mm->lru_record[i] = current_time_clock;

				ROHC_LOG_INFO(
					"found match ctx context [%d] for CID[%d]\n", i,
					ctx->cid);

				break;
			}

			if (lru_time < mm->lru_record[i]) {
				lru_time = mm->lru_record[i];
				lru_idx = i;
			}
		} else if (free_idx == INVALID_COMP_CTX_INDEX) {
			free_idx = i;
		}
	}

	if (ctx == NULL) {
		u16 idx;

		if (free_idx != INVALID_COMP_CTX_INDEX) {
			idx = free_idx;
			ROHC_LOG_INFO(
				"alloc new context [%d] for CID[%d]\n",
				idx,
				cid);
		} else if (lru_idx != INVALID_COMP_CTX_INDEX) {
			idx = lru_idx;

			ROHC_LOG_INFO(
				"reuse context [%d] for CID[%d]\n",
				idx,
				cid);
		} else {
			return NULL;
		}

		mm->lru_record[idx] = current_time_clock;

		ctx = &mm->ctx_array[idx];
		memset(ctx, 0, sizeof(rohc_decomp_context_t));

		ctx->in_use = true;
		ctx->cid = cid;
	}

	return ctx;
}

static rohc_decomp_status_t  rohc_extract_payload(
		net_buf_t * const payload_buf,
		const net_buf_t rohc_buf,
		const u16 hdr_size)
{
	u8 *payload = NULL;
	u16 payload_size = 0;

	if (ATSC30_NULL_PTR_CHECK(payload_buf))
		return ROHC_DECOMP_INVALID_COMPRESSOR;
	if (ATSC30_NULL_PTR_CHECK(rohc_buf.data))
		return ROHC_DECOMP_OUTPUT_BUFFER_ERROR;

	payload = net_buf_get_ptr(rohc_buf, hdr_size);

	payload_size = net_buf_data_size(rohc_buf) - hdr_size;
	*payload_buf = net_buf_init_full(payload, payload_size);

	return ROHC_DECOMP_SUCCESS;
}

//-------------------------------------------------------------------------------------------------
//  Public Functions
//-------------------------------------------------------------------------------------------------
rohc_decomp_status_t rohc_decomp_priv_decompress(
		rohc_decompressor_t *decomp,
		net_buf_t *uncomp_pkt,
		net_buf_t rohc_pkt)
{
	rohc_decomp_status_t ret;
	net_buf_t payload_buf;
	rohc_decomp_context_t *ctx;
	u8 cid;
	u8 non_cid_1st_oct;
	u8 non_cid_2nd_oct_idx;

	if (ATSC30_NULL_PTR_CHECK(decomp))
		return ROHC_DECOMP_INVALID_COMPRESSOR;
	if (ATSC30_NULL_PTR_CHECK(uncomp_pkt))
		return ROHC_DECOMP_OUTPUT_BUFFER_ERROR;

	if (rohc_pkt.len >= 8) {
		atsc30_log_dump_hex_array(
			A30_DBG_LVL_VERBOS,
			ATSC30_LOG_MODULE_ROHC,
			rohc_pkt.data,
			min((size_t)8, (size_t)(rohc_pkt.len)),
			sizeof(rohc_pkt.data[0]),
			"ROHC packet data dump 8 bytes");
	}

	if (!rohc_packet_decode_rohc_cid(
		rohc_pkt,
		decomp->cid_type,
		&cid,
		&non_cid_1st_oct,
		&non_cid_2nd_oct_idx))
		return ROHC_DECOMP_CID_ERROR;

	if (cid > decomp->max_cid) {
		ROHC_LOG_WARN(
			"cid %d > max_cid %d\n",
			cid,
			decomp->max_cid);

		return ROHC_DECOMP_INVALID_CID;
	}

	ctx = find_decomp_context(decomp, cid);

	if (ctx == NULL) {
		ROHC_LOG_WARN(
			"no available decompress context available\n");

		return ROHC_DECOMP_NO_CONTEXT;
	}

	ctx->packet_type = rohc_packet_decode_packet_type(non_cid_1st_oct);

	if (ctx->packet_type == ROHC_PACKET_UNKNOWN)
		return ROHC_DECOMP_PACKER_TYPE_ERROR;

	ctx->en_ip_dyn_ext_field = decomp->aux_cfg.en_ip_dyn_ext_1_byte_filed;

	ret = decode_rohc_packet_header(
			ctx,
			rohc_pkt,
			non_cid_1st_oct,
			non_cid_2nd_oct_idx);

	if (ret != ROHC_DECOMP_SUCCESS)
		return ret;

	ret = rohc_extract_payload(
			&payload_buf,
			rohc_pkt,
			ctx->header_size);

	if (ret != ROHC_DECOMP_SUCCESS)
		return ret;

	ret = rohc_decomp_network_build_packet(
			&ctx->net_ctx,
			uncomp_pkt,
			payload_buf,
			ctx->packet_type);

	return ret;
}
