/***************************************************************************//**
 @defgroup lip_ip IP

******************************************************************************/

/***************************************************************************//**
 @addtogroup lip_ip
 @{
 @file lip_ipv4.h
 @brief

 @author Borisov Alexey <borisov@lcard.ru>
 @date   26.08.2010
*******************************************************************************/


#ifndef LIP_IPV4_H_
#define LIP_IPV4_H_



#include "lip/lip_defs.h"
#include "lip/net/ipv4/lip_ip_link_local.h"
#include "lcspec.h"

#include <string.h>

/** Размер адреса для протокола IPv4 */
#define LIP_IPV4_ADDR_SIZE      4

typedef uint8_t t_lip_ipv4_addr[LIP_IPV4_ADDR_SIZE];


#define lip_ipv4_addr_equ(addr1, addr2) ((addr1[0] == addr2[0]) && \
                                        (addr1[1] == addr2[1]) && \
                                        (addr1[2] == addr2[2]) && \
                                        (addr1[3] == addr2[3]))


#define lip_ipv4_addr_cpy(da, sa)  memcpy(da,sa, LIP_IPV4_ADDR_SIZE)

#define lip_ipv4_addr_set_invalid(_addr) memset(_addr, 0, LIP_IPV4_ADDR_SIZE)


//проверка, принадлежит ли адрес данной сети
#define lip_ipv4_addr_chk_msk(addr1, addr2, msk) (((addr1[0]&msk[0]&0xFF) == (addr2[0]&msk[0]&0xFF)) && \
                                        ((addr1[1]&msk[1]&0xFF) == (addr2[1]&msk[1]&0xFF)) && \
                                        ((addr1[2]&msk[2]&0xFF) == (addr2[2]&msk[2]&0xFF)) && \
                                        ((addr1[3]&msk[3]&0xFF) == (addr2[3]&msk[3]&0xFF)))

//проверка, что это широковещательный адрес для данной сети
#define lip_ipv4_addr_is_bcast(addr1, msk) ((((addr1[0]&~msk[0])&0xFF) == (~msk[0]&0xFF)) && \
                                        (((addr1[1]&~msk[1])&0xFF) == (~msk[1]&0xFF)) && \
                                        (((addr1[2]&~msk[2])&0xFF) == (~msk[2]&0xFF)) && \
                                        (((addr1[3]&~msk[3])&0xFF) == (~msk[3]&0xFF)))
//проверка, что это адрес local host (0) для данной сети
#define lip_ipv4_addr_is_localhost(addr1, msk) (!(addr1[0]&msk[0])&& \
                                        !(addr1[1]&msk[1])&& \
                                        !(addr1[2]&msk[2])&& \
                                        !(addr1[3]&msk[3]))


//проверка, что заданный ipv4 адрес является мультикастным
#define lip_ipv4_addr_is_mcast(_addr) ((_addr[0] >= 224) && (_addr[0] <= 239))

#define lip_ipv4_addr_is_valid(_addr) ((_addr[0]!=0) || (_addr[1]!=0) || (_addr[2]!=0) || (_addr[3]!=0))

/* проверка, что это "Private Use IPv4" - адресс действительный только
 * внутри сети - rfc1918 */
#define lip_ipv4_addr_is_private(_addr) ((_addr[0] == 10) || \
           ((_addr[0]==172) && (_addr[1] >= 16) && (_addr[1] < 32)) \
           ((_addr[0]==192) && (_addr[1]==168))

/* проверка, что это loopback адрес - rfc5735 */
#define lip_ipv4_addr_is_loopback(_addr) (_addr[0]==127)


/* проверка, что адрес действительный (без привязки к маски) */
#define lip_ipv4_addr_is_unicast(_addr) (!lip_ipv4_addr_is_mcast(_addr) && \
                                         !lip_ipv4_addr_is_loopback(_addr))
/* проверка, что адрес действительный и не является link-local */
#define lip_ipv4_addr_is_routable(_addr) (lip_ipv4_addr_is_unicast(_addr) && \
                                           !lip_ipv4_is_link_local(_addr))

/** @todo максрос is_unicast с привязкой к маске */



//текущий ip-адрес модуля



const uint8_t *lip_ipv4_cur_addr(void);
const uint8_t *lip_ipv4_cur_mask(void);
const uint8_t *lip_ipv4_cur_gate(void);

int lip_ipv4_cur_addr_is_valid(void);


typedef enum {
    /** признак, что необходимо сделать аннонс адреса с помощью ARP */
    LIP_IPV4_ADDR_FLAG_ARP_ANNOUNCE  = 1 << 0
} t_lip_ipv4_addr_falgs;

t_lip_errs lip_ipv4_set_addr_ex(const uint8_t *ip_addr, unsigned flags);

static LINLINE t_lip_errs lip_ipv4_set_addr(const uint8_t *ip_addr) {
    return lip_ipv4_set_addr_ex(ip_addr,
                                0
#ifdef LIP_IPV4_USE_ADDR_ANNOUNCE
                                | LIP_IPV4_ADDR_FLAG_ARP_ANNOUNCE
#endif
                                );
}

t_lip_errs lip_ipv4_set_mask(const uint8_t *mask);
t_lip_errs lip_ipv4_set_gate(const uint8_t *gate);

#endif /* LIP_IP_H_ */

/** @}*/
