#include "version.h"
#include "type.h"
#include "ar168.h"
#include "apps.h"
#include "core.h"
#include "tcpip.h"

#include "bank2.h"

#define IP_VERSION      4   /* current version value */
#define IP_MINHLEN      5   /* minimum header length (in longs) */
#define IP_INIT_TTL     128 /* initial time-to-live value */

UCHAR _iAckID;
UCHAR _iLayer3Qos;

void IpInit()
{
	_iAckID = 1;
	_iLayer3Qos = OptionsGetByte(OPT_LAY3_QOS);
}

void IpSendData(USHORT sLen, PCHAR pDstIP, UCHAR iProtocol)
{
	PCHAR pIPLayer;
	USHORT sMax;

	// ip layer
	pIPLayer = (PCHAR)(Adapter_pPacketBuf + EP_DATA);
	memset((PCHAR)(pIPLayer + IP_ID), 0, (IP_SRC - IP_ID));
	pIPLayer[IP_VERLEN] = (IP_VERSION << 4) + IP_MINHLEN;
	pIPLayer[IP_TOS] = _iLayer3Qos;
//	pIPLayer[IP_TOS] = IPP_NORMAL;
	pIPLayer[IP_ID + 1] = _iAckID;
	pIPLayer[IP_TTL] = IP_INIT_TTL;
	pIPLayer[IP_PROTO] = iProtocol;
	memcpy4((PCHAR)(pIPLayer + IP_SRC), Sys_pIpAddress);
	memcpy4((PCHAR)(pIPLayer + IP_DST), pDstIP);

	sMax = (Sys_iIpType == IP_TYPE_PPPOE) ? (IP_DATA_MAX_SIZE - PPPOE_INFO): IP_DATA_MAX_SIZE;
	if (sLen > sMax)
	{
		USHORT2PCHAR(sMax + IP_DATA, (PCHAR)(pIPLayer + IP_LEN));
		USHORT2PCHAR(IP_MF, (PCHAR)(pIPLayer + IP_FRAGOFF));
		USHORT2PCHAR_L(ip_checksum(short_sum(pIPLayer, IP_DATA)), (PCHAR)(pIPLayer + IP_CKSUM)); 
#ifdef SYS_PPPOE
		if (Sys_iIpType == IP_TYPE_PPPOE)
		{
			PppoeSendData(ETHERNET_MAX_SIZE - EP_DATA - PPPOE_INFO);
		}
		else
#endif
		{
			ArpSendData(ETHERNET_MAX_SIZE, pDstIP);
		}

		USHORT2PCHAR(0, (PCHAR)(pIPLayer + IP_CKSUM));
		sLen -= sMax;
		USHORT2PCHAR((sMax >> 3), (PCHAR)(pIPLayer + IP_FRAGOFF));
		memcpy((PCHAR)(pIPLayer + IP_DATA), (PCHAR)(pIPLayer + IP_DATA + sMax), sLen);
	}

	USHORT2PCHAR(sLen + IP_DATA, (PCHAR)(pIPLayer + IP_LEN));
	USHORT2PCHAR_L(ip_checksum(short_sum(pIPLayer, IP_DATA)), (PCHAR)(pIPLayer + IP_CKSUM)); 		// calculate and fill ip layer check sum

#ifdef SYS_PPPOE
	if (Sys_iIpType == IP_TYPE_PPPOE)
	{
		PppoeSendData(sLen + IP_DATA);
	}
	else
#endif
	{
		ArpSendData(sLen + EP_DATA + IP_DATA, pDstIP);
	}

	_iAckID ++;
}

/*
ULONG PseudoHeaderCheckSum(USHORT sLen, PCHAR pSrcIP, PCHAR pDstIP, UCHAR iProtocol)
{
	UCHAR pBuf[12];

	// make 12 bytes pseudo-header
	memcpy4(pBuf, pSrcIP);
	memcpy4((PCHAR)(pBuf + IP_ALEN), pDstIP);
	USHORT2PCHAR(iProtocol, (PCHAR)(pBuf + IP_ALEN + IP_ALEN));
	USHORT2PCHAR(sLen, (PCHAR)(pBuf + IP_ALEN + IP_ALEN + 2));

	return short_sum(pBuf, 12);
}
*/
