/*
 * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the following
 *    disclaimer in the documentation and/or other materials provided
 *    with the distribution.
 *  * Neither the name of The Linux Foundation nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>
#include <cstring> // for memcpy
#include "hton.h" // for htonl
#include "InterfaceAbstraction.h"
#include "Constants.h"
#include "Logger.h"
#include "TestsUtils.h"
#include "Filtering.h"
#include "HeaderInsertion.h"
#include "RoutingDriverWrapper.h"
#include "IPAFilteringTable.h"

/*
Processing context test design:

1.	1 Producer with RNDIS de-aggregation and ETH2 header removal.
2.	1 Producer with WLAN and ETH2 header removal.
3.	1 default consumer.
4.	1 RNDIS aggregation consumer.
5.	1 FLT rule – accept all - points to 1 RT rule.
6.	1 RT rule – accept all - points to specific test relevant proc_ctx.
7.	All tests add all proc_ctx  (for all tests).
8.	Proc_ctx to be added: 1 for each test – 3 altogether.
	Proc_ctx of test 01 and 03 are the same.
9.	Each test will send 1 packet and check that the packet is good
	except test 03.
10.	Test 03  the same as Test 01  but will send multiple packets
	and expect 1 (RNDIS aggregation test).

List of tests:
00.	Header insertion scenario of [RNDIS][ETH_II][IP] -> [WLAN][ETH_II][IP]
01.	Header insertion scenario of [WLAN][ETH_II][IP] -> [RNDIS][ETH_II][IP]
02.	Header insertion scenario of [WLAN][ETH_II][IP] -> [WLAN’][ETH_II][IP]
03.	Header insertion of [WLAN][ETH_II][IP] -> [RNDIS][ETH_II][IP]
	with RNDIS aggregation.
04.	Header insertion scenario when adding total header sizes > 2048
05.	Header insertion scenario of [ETH_II][IP] -> [WLAN][ETH_II][IP]
06.	Header insertion scenario of [WLAN][ETH_II][IP] -> [ETH_II][IP
07.	Header insertion scenario of [ETH_II][IP] -> [ETH_II][IP]
08.	Header insertion scenario of [RNDIS][ETH_II][IP] -> [WLAN][802.3][IP]
09.	Header insertion scenario of [WLAN][802.3][IP] -> [RNDIS][ETH_II][IP]
10.	Header insertion scenario of [ETH_II][IP] -> [WLAN][802.3][IP]
11.	Header insertion scenario of [WLAN][802.3][IP] -> [WLAN’][802.3][IP]
*/
class IpaHdrProcCtxTestFixture : public TestBase
{
public:
	enum HeaderHandleId
	{
		HEADER_HANDLE_ID_WLAN_ETH2,
		HEADER_HANDLE_ID_RNDIS_ETH2,
		HEADER_HANDLE_ID_ETH2,
		HEADER_HANDLE_ID_WLAN_802_3,
		HEADER_HANDLE_ID_VLAN_802_1Q,
		HEADER_HANDLE_ID_MAX
	};

	enum ProcCtxHandleId
	{
		PROC_CTX_HANDLE_ID_ETH2_2_WLAN_ETH2,
		PROC_CTX_HANDLE_ID_ETH2_2_RNDIS_ETH2,
		PROC_CTX_HANDLE_ID_ETH2_ETH2_2_ETH2,
		PROC_CTX_HANDLE_ID_WLAN_ETH2_2_802_3,
		PROC_CTX_HANDLE_ID_RNDIS_802_3_2_ETH2,
		PROC_CTX_HANDLE_ID_WLAN_802_3_2_ETH2,
		PROC_CTX_HANDLE_ID_802_1Q_2_802_1Q,
		PROC_CTX_HANDLE_ID_ETH2_2_802_1Q,
		PROC_CTX_HANDLE_ID_802_1Q_2_ETH2,
		PROC_CTX_HANDLE_ID_ETH2_ETH2_2_ETH2_EX,
		PROC_CTX_HANDLE_ID_MAX
	};

	// header table consist of 9 bits and 4B units -> 2048
	static const int m_ALL_HEADER_SIZE_LIMIT = 2048;

	static const size_t m_BUFF_MAX_SIZE =
		2 * RNDISAggregationHelper::RNDIS_AGGREGATION_BYTE_LIMIT;

	// [WLAN][ETH2] header
	static const Byte WLAN_ETH2_HDR[WLAN_ETH2_HDR_SIZE];

	// [ETH2] header
	static const Byte ETH2_HDR[ETH_HLEN];

	// [ETH2_802_1Q] vlan header
	static const Byte ETH2_8021Q_HDR[ETH8021Q_HEADER_LEN];

	// [WLAN][802.3] header
	static const Byte WLAN_802_3_HDR[WLAN_802_3_HDR_SIZE];

	static Filtering m_filtering;
	static RoutingDriverWrapper m_routing;
	static HeaderInsertion m_headerInsertion;

	// For each header type the handle is saved
	// to be used by the processing context
	uint32_t m_headerHandles[HEADER_HANDLE_ID_MAX];

	// For each prco_ctx type the handle is saved
	// to be used by the routing rule
	uint32_t m_procCtxHHandles[PROC_CTX_HANDLE_ID_MAX];

	// proc_ctx handle ID
	ProcCtxHandleId m_procCtxHandleId;

	// routing table handle
	uint32_t m_routingTableHdl;

	// Pipe with RNDIS and ETH2 header removal
	InterfaceAbstraction m_rndisEth2Producer;

	// Pipe with WLAN and ETH2 header removal
	InterfaceAbstraction m_wlanEth2producer;

	// Pipe with ETH2 header removal
	InterfaceAbstraction m_eth2Producer;

	// TODO: Pipe with WLAN and 802.3 header removal
	InterfaceAbstraction m_wlan802_3producer;

	// Pointer to current producer pipe used in the test
	InterfaceAbstraction *m_pCurrentProducer;
	ipa_client_type m_currProducerClient;

	// Pipe of the WLAN ETH2 consumer
	InterfaceAbstraction m_defaultConsumer;

	// Pipe of the RNDIS ETH2 consumer
	InterfaceAbstraction m_rndisEth2Consumer;

	// Pointer to current consumer pipe used in the test
	InterfaceAbstraction *m_pCurrentConsumer;
	ipa_client_type m_currConsumerPipeNum;

	// First input packet
	Byte m_sendBuffer1[m_BUFF_MAX_SIZE];
	size_t m_sendSize1;

	// Second input packet
	Byte m_sendBuffer2[m_BUFF_MAX_SIZE];
	size_t m_sendSize2;

	// First expected packet
	Byte m_expectedBuffer1[m_BUFF_MAX_SIZE];
	size_t m_expectedBufferSize1;

	enum ipa_ip_type m_IpaIPType;

	IpaHdrProcCtxTestFixture();

	virtual bool Setup();
	virtual bool Teardown();
	virtual void AddAllHeaders();

	// Insert a single header
	virtual void AddHeader(HeaderHandleId handleId);
	virtual void AddAllProcCtx();

	// Insert a single proc_ctx
	virtual void AddProcCtx(ProcCtxHandleId handleId);
	virtual void AddRtBypassRule(uint32_t hdrHdl, uint32_t procCtxHdl);
	virtual void AddFltBypassRule();
	virtual bool LoadPackets(enum ipa_ip_type ip) = 0;

	virtual bool ReceivePacketsAndCompare();

	// Create 1 IPv4 bypass routing entry and commits it
	virtual bool CreateIPv4BypassRoutingTable (
		const char *name,
		uint32_t hdrHdl,
		uint32_t procCtxHdl);

	virtual bool GenerateExpectedPackets() = 0;

	virtual bool AddRules();

	virtual bool SendPackets();

	virtual bool Run();

	~IpaHdrProcCtxTestFixture();

private:
};