/*
 * \brief  Ethernet protocol
 * \author Stefan Kalkowski
 * \date   2010-08-19
 */

/*
 * Copyright (C) 2010-2012 Genode Labs GmbH
 *
 * This file is part of the Genode OS framework, which is distributed
 * under the terms of the GNU General Public License version 2.
 */

#ifndef _NET__ETHERNET_H_
#define _NET__ETHERNET_H_

/* Genode includes */
#include <base/exception.h>
#include <util/string.h>

#include <util/endian.h>
#include <net/netaddress.h>

namespace Net {

	/**
	 * The data-layout of this class conforms to the Ethernet II frame
	 * (IEEE 802.3).
	 *
	 * Ethernet-frame-header-format:
	 *
	 *  ----------------------------------------------------------
	 * | destination mac address | source mac address | ethertype |
	 * |      6 bytes            |     6 bytes        |  2 bytes  |
	 *  ----------------------------------------------------------
	 */
	class Ethernet_frame
	{
		public:

			enum Size {
				ADDR_LEN  = 6, /* MAC address length in bytes */
			};

			typedef Network_address<ADDR_LEN> Mac_address;

			static const Mac_address BROADCAST;  /* broadcast address */

		private:

			Genode::uint8_t  _dst_mac[ADDR_LEN]; /* destination mac address */
			Genode::uint8_t  _src_mac[ADDR_LEN]; /* source mac address */
			Genode::uint16_t _type;              /* encapsulated protocol */
			unsigned         _data[0];           /* encapsulated data */

		public:

			class No_ethernet_frame : Genode::Exception {};


			/**
			 * Id representing encapsulated protocol.
			 */
			enum Ether_type {
				IPV4              = 0x0800,
				ARP               = 0x0806,
				WAKE_ON_LAN       = 0x0842,
				SYN3              = 0x1337,
				RARP              = 0x8035,
				APPLETALK         = 0x809B,
				AARP              = 0x80F3,
				VLAN_TAGGED       = 0x8100,
				IPX               = 0x8137,
				NOVELL            = 0x8138,
				IPV6              = 0x86DD,
				MAC_CONTROL       = 0x8808,
				SLOW              = 0x8809,
				COBRANET          = 0x8819,
				MPLS_UNICAST      = 0x8847,
				MPLS_MULTICAST    = 0x8848,
				PPPOE_DISCOVERY   = 0x8863,
				PPPOE_STAGE       = 0x8864,
				NLB               = 0x886F,
				JUMBO_FRAMES      = 0x8870,
				EAP               = 0x888E,
				PROFINET          = 0x8892,
				HYPERSCSI         = 0x889A,
				ATAOE             = 0x88A2,
				ETHERCAT          = 0x88A4,
				PROVIDER_BRIDGING = 0x88A8,
				POWERLINK         = 0x88AB,
				LLDP              = 0x88CC,
				SERCOS_III        = 0x88CD,
				CESOE             = 0x88D8,
				HOMEPLUG          = 0x88E1,
				MAC_SEC           = 0x88E5,
				PRECISION_TIME    = 0x88F7,
				CFM               = 0x8902,
				FCOE              = 0x8906,
				FCOE_Init         = 0x8914,
				Q_IN_Q            = 0x9100,
				LLT               = 0xCAFE
			};


			/*****************
			 ** Constructor **
			 *****************/

			Ethernet_frame(Genode::size_t size) {
				/* at least, frame header needs to fit in */
				if (size < sizeof(Ethernet_frame))
					throw No_ethernet_frame();
			}


			/***********************************
			 ** Ethernet field read-accessors **
			 ***********************************/

			/**
			 * \return destination MAC address of frame.
			 */
			Mac_address dst() { return Mac_address(&_dst_mac); }

			/**
			 * \return source MAC address of frame.
			 */
			Mac_address src() { return Mac_address(&_src_mac); }

			/**
			 * \return EtherType - type of encapsulated protocol.
			 */
			Genode::uint16_t type() { return bswap(_type); }

			/**
			 * \return payload data.
			 */
			void *data() { return &_data; }


			/***********************************
			 ** Ethernet field write-accessors **
			 ***********************************/

			/**
			 * Set the destination MAC address of this frame.
			 *
			 * \param mac  MAC address to be set.
			 */
			void dst(Mac_address mac) { mac.copy(&_dst_mac); }

			/**
			 * Set the source MAC address of this frame.
			 *
			 * \param mac  MAC address to be set.
			 */
			void src(Mac_address mac) { mac.copy(&_src_mac); }

			/**
			 * Set type of encapsulated protocol.
			 *
			 * \param type  the EtherType to be set.
			 */
			void type(Genode::uint16_t type) { _type = bswap(type); }


			/***************
			 ** Operators **
			 ***************/

			/**
			 * Placement new operator.
			 */
			void * operator new(Genode::size_t size, void* addr) {
				return addr; }

	} __attribute__((packed));
}

#endif /* _NET__ETHERNET_H_ */
