/*
 * Copyright 2015 Mario Richter, Peter Stephan
 * This file is part of NeMo.
 *
 * NeMo is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * NeMo is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with NeMo.  If not, see <http://www.gnu.org/licenses/>.
 */

/*!
 * \file net.h
 * \ingroup	net
 * \brief	Headerfile für die Netzwerk-Routinen zur IP-Kommunikation.
 */

#ifndef __NET_H__
#define __NET_H__


// --------------------------------------
// Defines

// Packet-Größen
#define PACKET_BUF_SIZE				600									//!< Maximale Packetgröße (= MTU, maximum transmission unit)
#define ARP_REPLY_LENGTH      60                  //!< Länge des ARP-Reply-Packets

// Packet-Typen
#define ETH_PACKET_TYPE_IPV4  0x0800              //!< Ethernet-Protokolltyp IP
#define ETH_PACKET_TYPE_ARP   0x0806              //!< Ethernet-Protokolltyp ARP

#define IP_PACKET_TYPE_TCP    6                   //!< IP-Protokolltyp TCP
#define IP_PACKET_TYPE_UDP    17                  //!< IP-Protokolltyp UDP
#define IP_PACKET_TYPE_ICMP   1                   //!< IP-Protokolltyp ICMP

#define IP_MAX_TTL            128                 //!< maximale (=default) TimeToLive für IP-Pakete

#define ICMP_ECHO_REQUEST     8                   //!< ICMP Echo Request (Ping)
#define ICMP_ECHO_ANSWER      0                   //!< ICMP Echo Antwort (Ping)

//ARP-Tabelle
#define ARP_MAX_ENTRIES       8 									//!< Max. Anzahl an Einträgen in ARP-Tabelle
#define ARP_ENTRY_LIFETIME    300                 //!< Lebensdauer eines ARP-Eintrags in Sekunden
#define ARP_OP_REQUEST        1                   //!< ARP Operationstyp Request
#define ARP_OP_REPLY          2                   //!< ARP Operationstyp Reply

//! Makro zum Ändern der Byte-Reihenfolge innerhalb eines Wortes (16 Bit)
#define HTONS(x)   ((((uint16_t)(x) & 0xFF00) >> 8) | \
                    (((uint16_t)(x) & 0x00FF) << 8))

//! Makro zum Ändern der Byte-Reihenfolge innerhalb eines 32-Bit-Integers
#define HTONL(x)   (((((uint32_t)(x) & 0xFF)) << 24) |      \
                    ((((uint32_t)(x) & 0xFF00)) << 8) |     \
                    ((((uint32_t)(x) & 0xFF0000)) >> 8) |   \
                    ((((uint32_t)(x) & 0xFF000000)) >> 24))

// Eigene IP-Adresse
#define MYIP_0        192                 //!< Eigene IP-Adresse (Byte 1)
#define MYIP_1        168                 //!< Eigene IP-Adresse (Byte 2)
#define MYIP_2        178                 //!< Eigene IP-Adresse (Byte 3)
#define MYIP_3        254                  //!< Eigene IP-Adresse (Byte 4)
#define MYIP					"192.168.178.254"		//!< String für den Status


// --------------------------------------
// Strukturen und Unions

//! Struktur für ARP-Tabelle
typedef struct
{
  uint8_t   mac[6];                               //!< MAC-Adresse
  uint8_t   ip[4];                                //!< IP-Adresse
  uint16_t  timer;                                //!< Lebensdauer des Eintrags (wird bei 0 ungültig)
}arpTableType;



//! TCP-Datenstruktur
typedef struct
{
  uint16_t  sourcePort;                           //!< TCP Quell-Port
  uint16_t  destPort;                             //!< TCP Ziel-Port
  uint32_t  sequenceNr;                           //!< TCP Sequenznummer
  uint32_t  acknowledgeNr;                        //!< TCP Acknowledge-Nummer
  uint8_t   dataOffset;                           //!< TCP Datenoffset (Bits 7..3)
  uint8_t   flags;                                //!< TCP Control-Flags (Bits 5..0)
  uint16_t  receiveWindow;                        //!< TCP Empfangsfenster
  uint16_t  checksum;                             //!< TCP Checksumme
  uint16_t  urgentPtr;                            //!< TCP Urgent Pointer
  uint8_t   data;                                 //!< TCP Erstes Datenbyte
}tcpType;

//! ICMP-Datenstruktur;
typedef struct
{
  uint8_t   type;                                 //!< ICMP Type
  uint8_t   code;                                 //!< ICMP Code
  uint16_t  checksum;                             //!< ICMP Checksumme
  uint16_t  id;                                   //!< ICMP ID (Identifizierung)
  uint16_t  seqNum;                               //!< ICMP Sequenznummer
}icmpType;

//! Union für verschiedene Protokolltypen unter IP
typedef union
{
  tcpType   tcp;                                  //!< TCP-Protokoll
  icmpType  icmp;                                 //!< ICMP-Protokoll
}dataType;

//! ARP-Datenstruktur
typedef struct
{
  uint16_t  hwAddrType;                           //!< ARP Hardwareadresstyp (1)
  uint16_t  protAddrType;                         //!< ARP Protokolladresstyp (0x0800)
  uint8_t   hwAddrSize;                           //!< ARP Hardwareadressgröße (6)
  uint8_t   protAddrSize;                         //!< ARP Protokolladressgröße (4)
  uint16_t  operation;                            //!< ARP Operation (1=Request, 2=Reply)
  uint8_t   sourceMac[6];                         //!< ARP Quell-MAC-Adresse
  uint8_t   sourceIp[4];                          //!< ARP Quell-IP-Adresse
  uint8_t   destMac[6];                           //!< ARP Ziel-MAC-Adresse
  uint8_t   destIp[4];                            //!< ARP Ziel-IP-Adresse
}arpType;

//! IP-Datenstruktur
typedef struct
{
  uint8_t   ipVerIhl;                             //!< IP Version und Headerlänge
  uint8_t   ipTos;                                //!< IP Type of Service
  uint16_t  ipLength;                             //!< IP Paketlänge
  uint16_t  ipId;                                 //!< IP Identifikation (für Fragmentierung)
  uint16_t  ipFlagsOffset;                        //!< IP Flags und Fragmentoffset (für Fragmentierung)
  uint8_t   ipTtl;                                //!< IP Time-to-live
  uint8_t   ipProtType;                           //!< IP Folgeprotokolltyp (TCP, UDP, ...)
  uint16_t  ipChecksum;                           //!< IP Checksumme
  uint8_t   ipSourceIp[4];                        //!< IP Quell-IP-Adresse
  uint8_t   ipDestIp[4];                          //!< IP Ziel-IP-Adresse

  dataType  data;
}ipType;

//! Union für ARP- und IP-Packets
typedef union
{
  ipType    ip;
  arpType   arp;
}ipArpType;

//! Ethernet-Paketaufbau
typedef struct
{
  /* ---- Ethernet-Packet ---- */
  uint8_t   destinationMac[6];                    //!< ETH Ziel-MAC-Adresse
  uint8_t   sourceMac[6];                         //!< ETH Quell-MAC-Adresse
  uint16_t  protType;                             //!< ETH Folgeprotokolltyp (meist IP)

  ipArpType ipArp;                                //!< IP- oder ARP-Packet
}pktstruct;

//! Union für Ethernet-Packet
typedef union
{
  uint8_t buf[PACKET_BUF_SIZE];                   //!< Packet Buffer
  pktstruct pkt;                                  //!< Packet Struktur
}pktType;


// --------------------------------------
// Globale Variablen

extern pktType        pack;  										  //!< Speicher für Packet
extern arpTableType   arpTable[];                 //!< ARP-Tabelle

extern uint8_t        newPacketPresent;						//!< Neues Packet verfügbar
extern uint8_t        myIpAddr[4];                //!< Eigene IP-Adresse
extern uint8_t   eeIpAddr[4];                //!< Eigene IP-Adresse (EEPROM)
extern uint16_t       ipIdCount;                  //!< ID-Counter für IP-Packets


// --------------------------------------
// Funktionsdeklarationen

void ipInitStack(void);
void ipHandlePacket(void);

void arpRefreshEntry(pktType * packet);
void arpRequest(uint8_t * ipAddr);
void arpReply(pktType * packet);
void arpTimer(void);
uint8_t * arpGetMac(uint8_t * ip);

void arpTableShow(uint8_t ind);
void arpTableClear(void);

void icmpHandlePacket(pktType * packet);

uint16_t calcChecksum(uint8_t * buf, uint16_t len);

#endif
