//------------------------------------------------------------------------------
//  TOPPERS/ASP Windows Debug Environment
//  Copyright (C) 2010-2013 Cores Co., Ltd. Japan
//------------------------------------------------------------------------------
// $Id: EtherPacket.cs 142 2013-03-29 13:06:16Z nagasima $
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Console
{
	public class EtherPacket
	{
		private byte[] m_Packet;

		public const ushort ETHTYPE_ARP = 0x0806;
		public const ushort ETHTYPE_IP = 0x0800;

		public const byte IP_PROTO_ICMP = 1;
		public const byte IP_PROTO_UDP = 17;
		public const byte IP_PROTO_UDPLITE = 170;
		public const byte IP_PROTO_TCP = 6;

		public EtherPacket(byte[] packet)
		{
			m_Packet = packet;
		}

		public byte[] Packet { get { return m_Packet; } }

		public static int Compare(byte[] buf1, int ofs1, byte[] buf2, int ofs2, int len)
		{
			int end = ofs1 + len;
			int ret = 0;

			for (; ofs1 < end; ofs1++, ofs2++)
			{
				ret = buf2[ofs2] - buf1[ofs1];
				if (ret != 0)
					break;
			}

			return ret;
		}

		public ushort Type
		{
			get { return BitConverter.ToUInt16(m_Packet, 12); }
		}

		public byte Version
		{
			get { return (byte)((m_Packet[14] >> 4) & 0x0F); }
		}

		public ushort HeaderChecksum
		{
			get { return BitConverter.ToUInt16(m_Packet, 14 + 10); }
			set { Buffer.BlockCopy(BitConverter.GetBytes(value), 0, m_Packet, 14 + 10, 2); }
		}

		public byte InternetHeaderLength
		{
			get { return (byte)(m_Packet[14] & 0x0F); }
		}

		public byte Protocol
		{
			get { return m_Packet[14 + 9]; }
		}

		public ip_addr Source
		{
			get { return new ip_addr(BitConverter.ToUInt32(m_Packet, 14 + 12)); }
		}

		public ip_addr Destination
		{
			get { return new ip_addr(BitConverter.ToUInt32(m_Packet, 14 + 16)); }
		}

		public ushort UDPChecksum
		{
			get { return BitConverter.ToUInt16(m_Packet, 14 + InternetHeaderLength * 4 + 6); }
			set { Buffer.BlockCopy(BitConverter.GetBytes(value), 0, m_Packet, 14 + InternetHeaderLength * 4 + 6, 2); }
		}

		public ushort TCPChecksum
		{
			get { return BitConverter.ToUInt16(m_Packet, 14 + InternetHeaderLength * 4 + 16); }
			set { Buffer.BlockCopy(BitConverter.GetBytes(value), 0, m_Packet, 14 + InternetHeaderLength * 4 + 16, 2); }
		}

		public void SetIPCheckSum()
		{
			ushort chksum = HeaderChecksum;

			HeaderChecksum = 0;

			chksum = lwip.inet_chksum(m_Packet, 14, (ushort)(InternetHeaderLength * 4));

			HeaderChecksum = chksum;
		}

		public void SetUDPChecksum()
		{
			ushort chksum = UDPChecksum;

			UDPChecksum = 0;

			pbuf p = new pbuf();
			p.payload = m_Packet;
			p.offset = 14 + InternetHeaderLength * 4;
			p.len = (ushort)(m_Packet.Length - p.offset);

			chksum = lwip.inet_chksum_pseudo(p, Source, Destination, IP_PROTO_UDP, p.len);

			UDPChecksum = chksum;
		}

		public void SetTCPChecksum()
		{
			ushort chksum = TCPChecksum;

			TCPChecksum = 0;

			pbuf p = new pbuf();
			p.payload = m_Packet;
			p.offset = 14 + InternetHeaderLength * 4;
			p.len = (ushort)(m_Packet.Length - p.offset);

			chksum = lwip.inet_chksum_pseudo(p, Source, Destination, IP_PROTO_TCP, p.len);

			TCPChecksum = chksum;
		}
	}
}
