/*
 * $Id: api6.h,v 1.2 1999/06/20 02:30:55 labovit Exp $
 * originally Id: api6.h,v 1.8 1998/07/28 13:34:37 masaki Exp 
 */

#include <config.h>
#ifdef HAVE_IPV6

#ifndef _API6_H
#define _API6_H
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h> /* inet_ntop defined there */

/*
 * The API draft defines only the way to have access in byte.
 * Many implementations provide 32-bit access but the field name may vary.
 */
struct _in6_addr32 {
    u_long _s6_addr32[4];
};

/*
 * These are not defined in the API draft
 */
#define IN6_IS_ADDR_UC_GLOBAL(a) \
    (((a)->s6_addr[0] & 0xe0) == 0x20)

#define IN6_ADDR_COPY(a, b) \
    (*(struct in6_addr *)(a) = *(struct in6_addr *)(b))

#define IN6_ADDR_COMP(a, b) ( \
    (((struct _in6_addr32 *)(a))->_s6_addr32[0] - \
        ((struct _in6_addr32 *)(b))->_s6_addr32[0]) || \
    (((struct _in6_addr32 *)(a))->_s6_addr32[1] -  \
        ((struct _in6_addr32 *)(b))->_s6_addr32[1]) || \
    (((struct _in6_addr32 *)(a))->_s6_addr32[2] -  \
        ((struct _in6_addr32 *)(b))->_s6_addr32[2]) || \
    (((struct _in6_addr32 *)(a))->_s6_addr32[3] -  \
        ((struct _in6_addr32 *)(b))->_s6_addr32[3]))

extern const struct in6_addr in6addr_any;

#ifndef INET6_ADDRSTRLEN
#define INET_ADDRSTRLEN    16
#define INET6_ADDRSTRLEN   46
#endif /* INET6_ADDRSTRLEN */

#ifndef IN6_IS_ADDR_UNSPECIFIED

#define IN6_IS_ADDR_UNSPECIFIED(a) ( \
    ((struct _in6_addr32 *)(a))->_s6_addr32[0] == 0 && \
    ((struct _in6_addr32 *)(a))->_s6_addr32[1] == 0 && \
    ((struct _in6_addr32 *)(a))->_s6_addr32[2] == 0 && \
    ((struct _in6_addr32 *)(a))->_s6_addr32[3] == 0)

#define IN6_IS_ADDR_LOOPBACK(a) ( \
    ((struct _in6_addr32 *)(a))->_s6_addr32[0] == 0 && \
    ((struct _in6_addr32 *)(a))->_s6_addr32[1] == 0 && \
    ((struct _in6_addr32 *)(a))->_s6_addr32[2] == 0 && \
    ((struct _in6_addr32 *)(a))->_s6_addr32[3] == htonl(1))

#define IN6_IS_ADDR_MULTICAST(a) ((a)->s6_addr[0] == 0xff)

#ifdef notdef
extern __inline__ IN6_IS_ADDR_LINKLOCAL (struct in6_addr *a)
{
    return ((a->s6_addr32[0] & __constant_htonl (0xFFC00000)) == 
	    __constant_htonl(0xFE800000));
}

extern __inline__ IN6_IS_ADDR_V4MAPPED (struct in6_addr *a)
{
    return ((a->s6_addr32[0] | a->s6_addr32[1] | a->s6_addr32[2]) == 0
            && (a->s6_addr32[3] & __constant_htonl (0xFF000000)));
}

#endif

#define IN6_IS_ADDR_LINKLOCAL(a) \
    ((a)->s6_addr[0] == 0xfe && ((a)->s6_addr[1] & 0xc0) == 0x80)

#define IN6_IS_ADDR_SITELOCAL(a) \
    ((a)->s6_addr[0] == 0xfe && ((a)->s6_addr[1] & 0xc0) == 0xc0)

#define IN6_IS_ADDR_V4MAPPED(a) ( \
    ((struct _in6_addr32 *)(a))->_s6_addr32[0] == 0 && \
    ((struct _in6_addr32 *)(a))->_s6_addr32[1] == 0 && \
    ((struct _in6_addr32 *)(a))->_s6_addr32[2] == htonl(0x0000ffff))

#define IN6_IS_ADDR_V4COMPAT(a) ( \
    ((struct _in6_addr32 *)(a))->_s6_addr32[0] == 0 && \
    ((struct _in6_addr32 *)(a))->_s6_addr32[1] == 0 && \
    ((struct _in6_addr32 *)(a))->_s6_addr32[2] == 0 && \
    ntohl(((struct _in6_addr32 *)(a))->_s6_addr32[3]) > 1)

#endif /* IN6_IS_ADDR_UNSPECIFIED */


#ifdef __linux__

#ifndef HAVE_LINUX_2_2_5_IPV6
#include <netinet6/in6.h>
#include <netinet6/ipv6.h>
#include <netinet6/icmpv6.h>
#endif /* HAVE_LINUX_2_2_5_IPV6 */

/* this should be for NRL's inet6 library, which has a different struct */

#ifndef IPV6_PKTINFO
/* old linux didn't have this */
#define IPV6_PKTINFO IPV6_RXINFO
#endif
#if !defined(CMSG_FIRSTHDR) && defined(CMSG_FIRST)
#define CMSG_FIRSTHDR(a) CMSG_FIRST(a)
#endif

#ifndef _LINUX_ICMPV6_H

struct icmp6_filter {
  uint32_t data[8];
};

struct icmp6_hdr {
   uint8_t     icmp6_type;   /* type field */
   uint8_t     icmp6_code;   /* code field */
   uint16_t    icmp6_cksum;  /* checksum field */
   union {
      uint32_t  icmp6_un_data32[1]; /* type-specific field */
      uint16_t  icmp6_un_data16[2]; /* type-specific field */
      uint8_t   icmp6_un_data8[4];  /* type-specific field */
   } icmp6_dataun;
};

#define icmp6_data32    icmp6_dataun.icmp6_un_data32
#define icmp6_data16    icmp6_dataun.icmp6_un_data16
#define icmp6_data8     icmp6_dataun.icmp6_un_data8
#define icmp6_pptr      icmp6_data32[0]  /* parameter prob */
#define icmp6_mtu       icmp6_data32[0]  /* packet too big */
#define icmp6_id        icmp6_data16[0]  /* echo request/reply */
#define icmp6_seq       icmp6_data16[1]  /* echo request/reply */
#define icmp6_maxdelay  icmp6_data16[0]  /* mcast group membership */

#endif /* _LINUX_ICMPV6_H */

#include <asm/bitops.h>

/* Linux and NRL have ICMPV6_... */

#define ICMP6_FILTER_WILLPASS(type, filterp) \
	 (test_bit(type, filterp) == 0)

#define ICMP6_FILTER_WILLBLOCK(type, filterp) \
	 test_bit(type, filterp)

#define ICMP6_FILTER_SETPASS(type, filterp) \
	 clear_bit(type & 0x1f, &((filterp)->data[type >> 5]))

#define ICMP6_FILTER_SETBLOCK(type, filterp) \
	 set_bit(type & 0x1f, &((filterp)->data[type >> 5]))

#define ICMP6_FILTER_SETPASSALL(filterp) \
	 memset(filterp, 0, sizeof(struct icmp6_filter));

#define ICMP6_FILTER_SETBLOCKALL(filterp) \
	 memset(filterp, 0xFF, sizeof(struct icmp6_filter));

#if !defined(ICMP6_FILTER) && defined(ICMPV6_FILTER)
#define ICMP6_FILTER ICMPV6_FILTER
#endif /* !defined(ICMP6_FILTER) && defined(ICMPV6_FILTER) */

#ifndef ICMP6_DST_UNREACH
#define ICMP6_DST_UNREACH             1
#define ICMP6_PACKET_TOO_BIG          2
#define ICMP6_TIME_EXCEEDED           3
#define ICMP6_PARAM_PROB              4
#endif /* ICMP6_DST_UNREACH */

#ifndef ND_ROUTER_SOLICIT
#define ND_ROUTER_SOLICIT           133
#define ND_ROUTER_ADVERT            134
#define ND_NEIGHBOR_SOLICIT         135
#define ND_NEIGHBOR_ADVERT          136
#define ND_REDIRECT                 137
#endif /* ND_ROUTER_SOLICIT */

#endif /* __linux__ */

/*
 * differences in multicast definitions
 */
#ifdef NRL_IPV6
#define ipv6mr_multiaddr i6mr_multiaddr
#define ipv6mr_interface i6mr_interface
#endif /* NRL_IPV6 */
#ifdef HAVE_IPV6MR_IFINDEX
#define ipv6mr_interface ipv6mr_ifindex
#endif /* HAVE_IPV6MR_IFINDEX */

#endif /* _API6_H */
#endif /* HAVE_IPV6 */
