/*
 * lip_ip_private.h
 *
 *  Created on: 05.08.2011
 *      Author: Borisov
 */

#ifndef LIP_IP_PRIVATE_H_
#define LIP_IP_PRIVATE_H_

#include "lip/net/lip_ip.h"
#include "lip/link/lip_eth_private.h"
#include "lcspec.h"

//коды протоколов верхнего уровня
#define LIP_PROTOCOL_ICMP  1
#define LIP_PROTOCOL_IGMP  2
#define LIP_PROTOCOL_TCP   6
#define LIP_PROTOCOL_UDP   17
#define LIP_PROTOCOL_ICMP6 58

typedef  enum {
    LIP_IP_FLAG_UNSPEC_LOCAL_IP     = 0x1U,
    LIP_IP_FLAG_BROADCAST           = 0x2U,
    LIP_IP_FLAG_MULTICAST           = 0x4U,
    //указывает, что нужно добавить соответствующую опции при посылке (rfc2113)
    LIP_IP_FLAG_ROUTER_ALERT        = 0x8U,

} t_lip_ip_flags;

typedef enum {
    //признак, что у принятой дейтаграммы неверный ip-адрес
    LIP_IP_RXFLAG_INVALID_DEST_ADDR   = 0x10U,
    //признак, что дейтаграмма не целая, а фрагмент
    LIP_IP_RXFLAG_FRAGMETED           = 0x20U
} t_lip_ip_rx_flags;

/***************  флаги, задающие Type Of Service ****************/
//значения поля precedence
#define LIP_IP_PRECEDENCE_NETWORK_CONTROL       0xE0
#define LIP_IP_PRECEDENCE_INTERNETWORK_CONTROL  0xC0
#define LIP_IP_PRECEDENCE_CRITIC_ECP            0xA0
#define LIP_IP_PRECEDENCE_FLASH_OVERRIDE        0x80
#define LIP_IP_PRECEDENCE_FLASH                 0x60
#define LIP_IP_PRECEDENCE_IMMEDIATE             0x40
#define LIP_IP_PRECEDENCE_PRIORITY              0x20
#define LIP_IP_PRECEDENCE_ROUTINE               0x00
//доп. флаги
#define LIP_IP_TOS_LOW_DELAY                    0x10
#define LIP_IP_TOS_HIGH_TROUGHPUT               0x08
#define LIP_IP_TOS_HIGH_RELIBILITY              0x04
/* флаги из заголовка */
#define LIP_IPV4_HDR_FLAG_DF                    0x40 /* Don't fragment */
#define LIP_IPV4_HDR_FLAG_MF                    0x20 /* More fragments */


//максимальный размер заголовка IPv4
#define LIP_IPV4_MAX_HDR_SIZE                     60

/*****************************************************************
 * структура содержит полезную информацию из заголовка IP-пакета,
 * которую могут использовать протоколы верхнего уровня
 *****************************************************************/
typedef struct {
    uint32_t flags;
    const uint8_t* sa; //указатель на ip-адрес источника пакета
    const uint8_t* da; //указатель на ip-адрес назначения пакета    
    t_lip_ip_type type; //тип протокола IP (для различия IPv4, IPv6)
    uint8_t addr_len;  //длина ip-адреса
    uint8_t protocol;  //код протокола верхнего уровня    
    uint8_t ttl;
    uint8_t tos; //type of service
} t_lip_ip_info;


#include "lcspec_pack_start.h"
//заголовок IPv4
struct st_lip_ipv4_hdr {
    uint8_t ver_ihl; //version | internet header length
    uint8_t tos; //Type of Service
    uint16_t length; //Total Length
    uint16_t id;    
    uint16_t offs_flgs; // Flags (3) + Fragment Offset (13)
    uint8_t time_to_live;
    uint8_t protocol;
    uint16_t checksum;
    uint8_t src_addr[LIP_IPV4_ADDR_SIZE];
    uint8_t dest_addr[LIP_IPV4_ADDR_SIZE];
    uint8_t opt[0];
} LATTRIBUTE_PACKED;
typedef struct st_lip_ipv4_hdr t_lip_ipv4_hdr;
#define LIP_IPV4_MIN_HDR_SIZE sizeof(struct st_lip_ipv4_hdr)
#include "lcspec_pack_restore.h"


typedef struct {
    const t_lip_eth_rx_packet *eth_packet;
    t_lip_payload pl;
    t_lip_ip_info ip_info;
    uint8_t hdr_size;  //размер заголовка IP
    const t_lip_ipv4_hdr *hdr;
    uint32_t rx_flags;
}  t_lip_ip_rx_packet;




void lip_ip_init(void);
void lip_ip_pull(void);
t_lip_errs lip_ip_process_packet(const t_lip_payload *pl, const t_lip_eth_rx_packet *eth_packet, t_lip_ip_rx_packet *ip_packet);

uint8_t* lip_ip_prepare(t_lip_ip_info *tx_info, int *max_size);

t_lip_errs lip_ip_flush_split(int size, const uint8_t* data, int data_size);
/***************************************************************************//**
 *  Передача подготовленного IP-пакета.
 *  Должна вызываться только после успешного вызова lip_ip_prepare() 
 *      до вызова lip_pull()
 *  @param[in]size  Размер данных для передачи протокола верхнего уровня
 *  @return         Код ошибки
 ******************************************************************************/
#define lip_ip_flush(size) lip_ip_flush_split(size, NULL, 0)



uint16_t lip_chksum(uint16_t sum, const uint8_t *data, int len);
t_lip_errs lip_ipv4_get_mcast_mac(const uint8_t *ip, uint8_t *mac);

void lip_ip_arp_resolve_cb(t_lip_ip_type ip_type, const uint8_t *mac, const uint8_t* ip_addr, uint32_t len);



/* функции для получения максимального размера данных транспортного уровня
 * для передачи и приема в одном IP-пакете при IP-заголовке без опций.
 * Соответствует GET_MAXSIZES для получения MSS_S и MSS_R из rfc1122 p70 */
/** @todo сейчас всегда фиксированыне значения. в будущем возможно использование
 * PathMTU Discovery и т.п. */
uint32_t lip_ip_get_max_send_size(const t_lip_ip_info *info);
uint32_t lip_ip_get_max_recv_size(const t_lip_ip_info *info);
/* функция получения предпологаемого размера ip-опций для данных параметров.
 * используется для коррекции размеров макс. данных на верхнем уровне
 * (объединить с lip_ip_get_max_send_size()/lip_ip_get_max_recv_size() нельзя,
 * т.к. в TCP для mss размер опций должен быть применен и к полученному от
 * другой строны размера пакета */
uint32_t lip_ip_get_options_size(const t_lip_ip_info *info);

#endif /* LIP_IP_PRIVATE_H_ */
