/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* bos72L src/bos/kernext/inet/in6_var.h 1.33.1.2                         */
/*                                                                        */
/* Licensed Materials - Property of IBM                                   */
/*                                                                        */
/* Restricted Materials of IBM                                            */
/*                                                                        */
/* COPYRIGHT International Business Machines Corp. 1997,2018              */
/* All Rights Reserved                                                    */
/*                                                                        */
/* US Government Users Restricted Rights - Use, duplication or            */
/* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.      */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/* @(#)14       1.33.1.2  src/bos/kernext/inet/in6_var.h, sockinc, bos72L, l2018_11B8 2/28/18 09:37:59 */
/*	$NetBSD: in_var.h,v 1.8 1994/06/29 06:38:13 cgd Exp $	*/

/*
 * Copyright (c) 1985, 1986, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */

#ifndef _NETINET_IN6_VAR_H_
#define _NETINET_IN6_VAR_H_

#include <sys/queue.h>

#include <sys/corralid.h>
#include <sys/protosw.h> /* Defect 786019 */

#ifndef CONST
#define CONST const
#endif
extern	struct domain inet6domain;
extern	CONST struct protosw inet6sw[];

/* We start with the hash chain infrastructure to manipulte
 * the interface address structure linked list as an array
 * of hashed entries
 */

struct in6ifaddr_hash {
	struct in6ifaddr_hash       *next;
	struct in6ifaddr_hash       *prev;
};

#define ia6hashtoinifaddr(hp)         \
        (struct in6_ifaddr *)((char *)(hp) - offsetof(struct in6_ifaddr, ia_hash))
#define in6ifaddrtohash(ia)        (&(ia->ia_hash))
#define IN6IFADDR_HASHSZ            59

#define IN6IFADDR_HASH(addr) ((addr) % IN6IFADDR_HASHSZ)

struct in6ifaddr_hash_table {
	struct in6ifaddr_hash    head;
};

extern struct in6ifaddr_hash_table in6ifaddr_hash_table[IN6IFADDR_HASHSZ];

/* Hash table chain head lock */
#if     defined(_KERNEL)
extern  DRW_lock      *in6ifaddr_hashchn_lock[IN6IFADDR_HASHSZ];
#endif

#define NET_CACHELINESIZE       128
/*
 * Including net_globals.h (where NET_CACHELINESIZE is defined) breaks nfs.
 * Hence we redefine NET_CACHELINESIZE here. These should be kept consistent.
 * This is also defined in route.h, in_var.h & in_pbc.h (because of build breaks
 * encountered when included through net_globals.h).
 */

/*
 * Interface address, IPv6 version.  One of these structures
 * is allocated for each interface with an IPv6 address.
 * The ifaddr structure contains the protocol-independent part
 * of the structure and is assumed to be first.
 */
struct in6_ifaddr {
	struct	ifaddr ia_ifa;		/* protocol-independent info */
#define	ia_ifp		ia_ifa.ifa_ifp
#define ia_flags	ia_ifa.ifa_flags
	TAILQ_ENTRY(in6_ifaddr) ia_list; /* list of IPv6 addresses */
	struct	sockaddr_in6 ia_addr;	/* space for interface name */
	struct	sockaddr_in6 ia_dstaddr; /* space for broadcast addr */
	struct	sockaddr_in6 ia_sockmask; /* space for general netmask */
	struct  in6ifaddr_hash ia_hash;  /* hash links */
	cid_t	ia_kcid;		/* kernel corral id */
	caddr_t send_if_common;		/* The SEND keys and necessary data */
	u_short ia_type;		/* type of address (i.e. temporary RFC3041) */
#define IAT_TEMP	0x1		/* temporary address RFC 3041 */
#define IAT_CGA		0x2		/* CGA address RFC 3972 */
	u_short ia_state;		/* autoconfiguration state of address */
#define IAS_PREFERRED	0	/* preferred address (default) */
#define IAS_DEPRECATED	1	/* deprecated address */
#define IAS_INVALID	2	/* invalid address */
	u_short  in6_flags;     /* Address source flag  */
#define IN6FLAG_OTHER     0x0001 /* Source of adr is unknown    */
#define IN6FLAG_AUTOCONF6 0x0002 /* Source of addr is autoconf6 */
#define IN6FLAG_NDPDHOST  0x0004 /* Source of addr is ndpd-host */
#define IN6FLAG_IFCONFIG  0x0008 /* Source of addr is ifconfig  */
};

struct	in6_aliasreq {
	char	ifra_name[IFNAMSIZ];		/* if name, e.g. "en0" */
	struct	sockaddr_in6 ifra_addr;
	struct	sockaddr_in6 ifra_dstaddr;
	struct	sockaddr_in6 ifra_mask;
};

#ifdef PHABRE1
struct  in6_clustreq {
	char    ifra_name[IFNAMSIZ];            /* if name, e.g. "en0" */
	struct  sockaddr_in6 ifra_addr;
	struct  sockaddr_in6 ifra_dstaddr;
	struct  sockaddr_in6 ifra_mask;
	u_short              ifra_flags;
};
#endif /* PHABRE1 */

struct	in6_aliasreq2 {
	char	ifra_name[IFNAMSIZ];		/* if name, e.g. "en0" */
	struct	sockaddr_in6 ifra_addr;
	struct	sockaddr_in6 ifra_dstaddr;
	struct	sockaddr_in6 ifra_mask;
	union {
		u_short ifra_type;
		u_short ifra_state;
		u_short ifra_origin; /* Addr source flag */
	} ifra_attr;
#define	ifra_type	ifra_attr.ifra_type
#define	ifra_state	ifra_attr.ifra_state
#define	ifra_origin	ifra_attr.ifra_origin
};
/* in the sin6_flowinfo field of ifra_addr for SIOCAIFADDR6 */
#define IN6_ADDR_TENTATIVE  0xffffffff

struct in6_ifreq {
	char	ifr_name[IFNAMSIZ];		/* if name, e.g. "en0" */
	struct	sockaddr_in6 ifr_Addr;
};
struct in6_ifreq2 {
	char	ifr_name[IFNAMSIZ];		/* if name, e.g. "en0" */
	struct	sockaddr_in6 ifr_Addr;
	union {
		u_short ifr_type;
		u_short ifr_state;
	} ifr_attr;
#define	ifr_type	ifr_attr.ifr_type
#define	ifr_state	ifr_attr.ifr_state
};

struct	in6_zonereq {
	char	ifra_name[IFNAMSIZ];		/* if name, e.g. "en0" */
	uint32_t ifrz_scope;
#ifndef ADDR6_NUMSCOPES /* possibly already defined if in.h is included */
#define ADDR6_NUMSCOPES 16 /* number of IPv6 scopes */
#endif
	uint32_t ifrz_zone[ADDR6_NUMSCOPES];
};

/*
 * Structure for for SIOCSIFADDRORI6 ioctl
 */
struct ifaddrorigin6 {
    char ifro_name[IFNAMSIZ];
    struct sockaddr_in6 ifro_addr;
    int ifro_origin;
};

/*
 * Given a pointer to an in6_ifaddr (ifaddr),
 * return a pointer to the addr as a sockaddr_in6.
 */
#define	IA_SIN6(ia) (&(((struct in6_ifaddr *)(ia))->ia_addr))
#define	IA_DSTSIN6(ia) (&(((struct in6_ifaddr *)(ia))->ia_dstaddr))

/* NOTE: All future private IOCTL definitions should be defined in 'in_private.h'. */ 

#define SIOCSIFADDR6  (int)_IOW('i', 12, struct in6_ifreq)   /* set ifnet address */
#define SIOCGIFADDR6 (int)_IOWR('i', 33, struct in6_ifreq)   /* get ifnet address */
#define SIOCSIFDSTADDR6  (int)_IOW('i', 14, struct in6_ifreq)/* set p-p address */
#define SIOCGIFDSTADDR6 (int)_IOWR('i', 34, struct in6_ifreq)/* get p-p address */
#define SIOCSIFNETMASK6 (int)_IOW('i', 22, struct in6_ifreq) /* set net addr mask */
#define SIOCGIFNETMASK6 (int)_IOWR('i', 37, struct in6_ifreq)/* get net addr mask */

#define SIOCDIFADDR6  (int)_IOW('i', 25, struct in6_ifreq)   /* delete IF addr */
#define SIOCAIFADDR6  (int)_IOW('i', 26, struct in6_aliasreq)/* add/chg IF alias */
#define SIOCFIFADDR6  (int)_IOW('i', 39, struct in6_ifreq)   /* put IF addr in front */
#define SIOCVIFADDR6  (int)_IOW('i', 40, struct in6_aliasreq) /* does nothing */

#define SIOCGTUGADDR6 (int)_IOW('i', 41, struct in6_ifreq)   /* get TUG real addr */
#define SIOCSTUGADDR6 (int)_IOW('i', 42, struct in6_ifreq)   /* set TUG real addr */

#define SIOCADDANY6   (int)_IOW('i', 43, struct in6_ifreq)   /* add an anycast */
#define SIOCDELANY6   (int)_IOW('i', 44, struct in6_ifreq)   /* delete an anycast */

#define SIOCGIFSITE6  (int)_IOWR('i', 45, struct ifreq)  /* get ifnet site */
#define SIOCSIFSITE6  (int)_IOW('i', 46, struct ifreq)   /* set ifnet site */

#define SIOCGIFZONE6  (int)_IOWR('i', 47, struct in6_zonereq)  /* get ifnet zone(s) */
#define SIOCSIFZONE6  (int)_IOW('i', 48, struct in6_zonereq)   /* set ifnet zone */
/* address origin for snmp (IPv6) */
#define SIOCSIFADDRORI6 (int)_IOW('i',142,struct ifaddrorigin6) /* set address origin */

#define SIOCAIFADDR6T  (int)_IOW('i', 50, struct in6_aliasreq2)/* add/chg IF alias and type */
#define SIOCGIFADDR6T  (int)_IOWR('i', 51, struct in6_aliasreq2)  /* get type of address */

#define SIOCSIFADDRSTATE6  (int)_IOW('i', 52, struct in6_aliasreq2)/* change address state */
#define SIOCGIFADDRSTATE6  (int)_IOWR('i', 53, struct in6_aliasreq2)  /* get address state */
#define SIOCGSRCFILTER6  (int)_IOWR('i', 53, struct group_source_filter_req) /* get multicast source filter */
#define SIOCACLADDR6 	(int)_IOW('i', 54, struct in6_aliasreq)/* add/chg IF alias */
#define SIOCDCLADDR6    (int)_IOW('i', 55, struct in6_ifreq)   /* delete IF addr */
#define SIOCSIFADDRFLAG6 (int)_IOW('i', 56, struct in6_aliasreq2)/* set address source flag */
#define SIOCGIFADDRFLAG6 (int)_IOWR('i', 57, struct in6_aliasreq2)/* get address source flag */

#if defined(_KERNEL)

#define IN6IFADDR_HASHCHNHEAD_LOCKINIT(index) \
	do { \
		NET_MALLOC(in6ifaddr_hashchn_lock[index], DRW_lock *, \
				sizeof(DRW_lock), M_LOCKF, M_WAITOK); \
		lock_alloc(in6ifaddr_hashchn_lock[index], \
				LOCK_ALLOC_PIN, IN6IFADDR_LOCK_FAMILY, -1); \
		drw_lock_init(in6ifaddr_hashchn_lock[index]); \
	} while (0)

#define IN6IFADDR_HASHCHNHEAD_LOCK_DECL()      	  int	_in6ifl_h, _in6ifrl_h

#define IN6IFADDR_HASHCHNHEAD_WRITE_LOCK(index) \
	do { \
		_in6ifl_h = i_disable(PL_IMP); \
		drw_lock_write(in6ifaddr_hashchn_lock[index]); \
	} while (0)

#define IN6IFADDR_HASHCHNHEAD_READ_LOCK(index) \
	do { \
		_in6ifrl_h = i_disable(PL_IMP); \
		drw_lock_read(in6ifaddr_hashchn_lock[index]); \
	} while (0)

#define IN6IFADDR_HASHCHNHEAD_WRITE_UNLOCK(index) \
	do { \
		drw_lock_done(in6ifaddr_hashchn_lock[index]); \
		i_enable(_in6ifl_h); \
	} while (0)

#define IN6IFADDR_HASHCHNHEAD_READ_UNLOCK(index) \
	do { \
		drw_lock_done(in6ifaddr_hashchn_lock[index]); \
		i_enable(_in6ifrl_h); \
	} while (0)


extern  simple_lock_data_t     in6ifaddr_lock;
#define IN6IFADDR_LOCKINIT()     {					\
	lock_alloc(&in6ifaddr_lock, LOCK_ALLOC_PIN, IN6IFADDR_LOCK_FAMILY, -1);\
	simple_lock_init(&in6ifaddr_lock);		\
}
#define IN6IFADDR_LOCK_DECL()	int	_in6ifl;
#define IN6IFADDR_WRITE_LOCK()   _in6ifl = disable_lock(PL_IMP, &in6ifaddr_lock)
#define IN6IFADDR_READ_LOCK()    _in6ifl = disable_lock(PL_IMP, &in6ifaddr_lock)
#define IN6IFADDR_UNLOCK()       unlock_enable(_in6ifl, &in6ifaddr_lock)

extern  simple_lock_data_t     flow6_lock;
#define FLOW6_LOCKINIT()     {					\
	lock_alloc(&flow6_lock, LOCK_ALLOC_PIN, FLOW6_LOCK_FAMILY, -1);\
	simple_lock_init(&flow6_lock);		\
}
#define FLOW6_LOCK_DECL()	int	_flow6l;
#define FLOW6_WRITE_LOCK()   _flow6l = disable_lock(PL_IMP, &flow6_lock)
#define FLOW6_READ_LOCK()    _flow6l = disable_lock(PL_IMP, &flow6_lock)
#define FLOW6_LOCK()    _flow6l = disable_lock(PL_IMP, &flow6_lock)
#define FLOW6_UNLOCK()       unlock_enable(_flow6l, &flow6_lock)

#define IN6ANYADDR_HASHCHNHEAD_LOCKINIT(index) {							\
	lock_alloc(&(in6anycast_hashchn_lock[index]._l), LOCK_ALLOC_PIN, IN6ANYA_LOCK_FAMILY, -1);   \
	simple_lock_init(&(in6anycast_hashchn_lock[index]._l));                                        \
}
#define IN6ANYADDR_HASHCHNHEAD_LOCK_DECL()      	  int	_in6anycast;
#define IN6ANYADDR_HASHCHNHEAD_WRITE_LOCK(index)  							\
	_in6anycast = disable_lock(PL_IMP, &(in6anycast_hashchn_lock[index]._l))
#define IN6ANYADDR_HASHCHNHEAD_READ_LOCK(index)   							\
	_in6anycast = disable_lock(PL_IMP, &(in6anycast_hashchn_lock[index]._l))
#define IN6ANYADDR_HASHCHNHEAD_WRITE_UNLOCK(index)							\
	unlock_enable(_in6anycast, &(in6anycast_hashchn_lock[index]._l))
#define IN6ANYADDR_HASHCHNHEAD_READ_UNLOCK(index) 							\
	unlock_enable(_in6anycast, &(in6anycast_hashchn_lock[index]._l))

extern  simple_lock_data_t     in6anyaddr_lock;
#define IN6ANYADDR_LOCKINIT()     {					\
	lock_alloc(&in6anyaddr_lock, LOCK_ALLOC_PIN, IN6ANYA_LOCK_FAMILY, -1);\
	simple_lock_init(&in6anyaddr_lock);		\
}
#define IN6ANYADDR_LOCK_DECL()	int	_in6ifl;
#define IN6ANYADDR_WRITE_LOCK()   _in6ifl = disable_lock(PL_IMP, &in6anyaddr_lock)
#define IN6ANYADDR_READ_LOCK()    _in6ifl = disable_lock(PL_IMP, &in6anyaddr_lock)
#define IN6ANYADDR_UNLOCK()       unlock_enable(_in6ifl, &in6anyaddr_lock)


TAILQ_HEAD(in6_ifaddrhead, in6_ifaddr);
extern  struct  in6_ifaddrhead in6_ifaddr;

extern LIST_HEAD(in6_anyhead, in6_anycast) in6_anyhead;

#define SAME_ADDR6_MASK(a, b, m)                        \
	( (((a).s6_addr32[0] & (m).s6_addr32[0]) ==     \
	((b).s6_addr32[0] & (m).s6_addr32[0])) &&    \
	(((a).s6_addr32[1] & (m).s6_addr32[1]) ==     \
	((b).s6_addr32[1] & (m).s6_addr32[1])) &&    \
	(((a).s6_addr32[2] & (m).s6_addr32[2]) ==     \
	((b).s6_addr32[2] & (m).s6_addr32[2])) &&    \
	(((a).s6_addr32[3] & (m).s6_addr32[3]) ==     \
	((b).s6_addr32[3] & (m).s6_addr32[3])) )

/*
 * Macro for finding the interface (ifnet structure) corresponding to one
 * of our IPv6 addresses.
 */
#define IN6ADDR_TO_IFP(addr, ifp) \
	/* struct in6_addr addr; */ \
	/* struct ifnet *ifp; */ \
{ \
	register struct in6_ifaddr *ia; \
        struct in6ifaddr_hash *hp;                                           \
        struct in6ifaddr_hash_table *tablep;                                 \
        int index;                                                           \
        IN6IFADDR_HASHCHNHEAD_LOCK_DECL();                                    \
        ifp = NULL;                                                          \
                                                                             \
        index = IN6IFADDR_HASH((addr).s6_addr32[3]);                         \
        IN6IFADDR_HASHCHNHEAD_READ_LOCK(index);                              \
        tablep = &in6ifaddr_hash_table[index];                               \
        for (hp = tablep->head.next; hp != &(tablep->head); hp = hp->next) { \
                ia = ia6hashtoinifaddr(hp);                                  \
                if (SAME_ADDR6(((ia->ia_ifp->if_flags & IFF_POINTOPOINT) ?   \
			IA_DSTSIN6(ia) : IA_SIN6(ia))->sin6_addr, addr)) {   \
                        (ifp) = ia->ia_ifp;                                  \
                        break;                                               \
                }                                                            \
        }                                                                    \
	if (ifp == NULL)                                                     \
          for (hp = tablep->head.next; hp != &(tablep->head); hp = hp->next) { \
                ia = ia6hashtoinifaddr(hp);                                  \
		if (ia->ia_ifp->if_flags & IFF_POINTOPOINT &&                \
		    SAME_ADDR6(IA_SIN6(ia)->sin6_addr, addr)) {              \
                        (ifp) = ia->ia_ifp;                                  \
                        break;                                               \
                }                                                            \
          }                                                                  \
                                                                             \
        IN6IFADDR_HASHCHNHEAD_READ_UNLOCK(index);                            \
}



/*
 * Macro for finding the IPv6 address structure (in6_ifaddr) corresponding
 * to a given interface (ifnet structure).
 */
#define IFP_TO_IA6(ifp, ia) \
	/* struct ifnet *ifp; */ \
	/* struct in6_ifaddr *ia; */ \
{ \
	struct in6ifaddr_hash *hp, *hphead; \
	int index; \
	IN6IFADDR_HASHCHNHEAD_LOCK_DECL(); \
\
        for(index = 0; index < IN6IFADDR_HASHSZ; index++) {               \
             if (in6ifaddr_hash_table[index].head.next !=                 \
                  &(in6ifaddr_hash_table[index].head)) {                  \
                    IN6IFADDR_HASHCHNHEAD_READ_LOCK(index);               \
                    hphead = &(in6ifaddr_hash_table[index].head);         \
                    hp = hphead->next;                                    \
                    if ((hp != hphead) && hp) {                           \
                             for(; (hp != hphead) && hp; hp = hp->next) { \
                                    (ia) = ia6hashtoinifaddr(hp);         \
                                    if ((ia)->ia_ifp == (ifp)) {          \
                                         IN6IFADDR_HASHCHNHEAD_READ_UNLOCK(index);   \
                                         break;                           \
                                    }                                     \
                              } /* hash chain for loop */                 \
                    }                                                     \
                    if ((ia)->ia_ifp == (ifp))                            \
                             break;                                       \
                    IN6IFADDR_HASHCHNHEAD_READ_UNLOCK(index);             \
               } /* if test for inifaddrs in this chain */                \
        } /* index for loop */                                            \
        if (ia && (ia)->ia_ifp != (ifp))                                  \
                ia = 0;                                                   \
}

#define IN6ADDR_TO_IA(addr, ia) \
        /* struct in6_addr addr; */ \
        /* struct in6_ifaddr *ia; */ \
{ \
	IN6IFADDR_LOCK_DECL() \
		\
		IN6IFADDR_READ_LOCK(); \
		for ((ia) = in6_ifaddr.tqh_first; (ia); (ia) = (ia)->ia_list.tqe_next) { \
				if ((ia)->ia_sockmask.sin6_addr.u6_addr.u6_addr8[0] != 0 && \
						SAME_ADDR6_MASK((ia)->ia_addr.sin6_addr, addr, \
							(ia)->ia_sockmask.sin6_addr)) \
					break; \
		} \
	IN6IFADDR_UNLOCK(); \
}

#define IN6ADDR_TO_IA_IFP(addr, ia, ifp) \
        /* struct in6_addr addr; */ \
        /* struct in6_ifaddr *ia; */ \
        /* struct ifnet *ifp; */ \
{ \
	IN6IFADDR_LOCK_DECL() \
		\
		IN6IFADDR_READ_LOCK(); \
		for ((ia) = in6_ifaddr.tqh_first; (ia); (ia) = (ia)->ia_list.tqe_next) { \
				if ((ia)->ia_sockmask.sin6_addr.u6_addr.u6_addr8[0] != 0 && \
						SAME_ADDR6_MASK((ia)->ia_addr.sin6_addr, addr, \
							(ia)->ia_sockmask.sin6_addr)) \
					break; \
		} \
	if ((ifp) != (struct ifnet*)NULL) \
		(ifp) = ((ia) == NULL) ? (struct ifnet*)NULL : (ia)->ia_ifp; \
			IN6IFADDR_UNLOCK(); \
}

#endif


struct source6_info{
	char si_mode;
	ushort num_src;
	ushort max_src;
	ushort refcount;
	struct in6_addr *si6_src;
	struct source6_info *si6_next;

};

/* Filter list per multicast group */
struct filter6_list {
	char    fl_mode;        /* Filter mode */
	ushort  num_src;        /* No. of source addresses in the list */
	ushort  max_src;        /* Max source addresses that can fit */
	struct in6_addr *fl6_src; /* Source list */
};

/* Include/Exclude addresses per group */
struct addr6_info {
	struct in6_addr addr6; /* Address list */
	ushort  count; /* Refcount/pending report count */
};

struct address6_list {
	ushort  num_src;        /* Number of sources in the list */
	ushort  max_src;        /* Max source addresses that can fit */
	struct addr6_info *al6_ai;
};

/*
 * IPv6 multicast address structure.  There is one of these for each IPv6
 * multicast group to which this host belongs on a given network interface.
 * They are kept in a linked list, rooted in the interface's in6_ifaddr
 * structure.
 */
struct in6_multi {
	LIST_ENTRY(in6_multi) inm6_entry; /* list glue */

	struct	in6_addr inm6_addr;	/* IPv6 multicast address */
	struct	ifnet *inm6_ifp;	/* back pointer to ifnet */
	ushort  exc6_count; /* no. sockets in exclude mode */
	ushort  si6count;		/* number of sockets having source info */
	struct source6_info *inm6_ui;   /* Source Address info */
	u_int	inm6_refcount;		/* no. membership claims by sockets */
	u_int	inm6_timer;		/* ICMPv6 membership report timer 
						   In MLDV2 , used to schedule State Change Reports */
	u_int	inm6_rtimer;		/* Schedule Current State Reports for received 
						   multicast address queries for MLDv2 */
	u_int	inm6_state;		/* state of the membership */
	u_int32	inm6_sin6_scope_id;	/* scope zone for this multicast addr. */
	struct  router6_info *inm6_rti;   /* router info */
	struct address6_list inm6_exc_list; /* list of excluded addresses */
	struct address6_list inm6_inc_list; /* list of included addresses */
	struct  filter6_list inm6_fl;     /* Consolidated source list */
	char    s6mode;  /* State change mode */
	ushort  state6_count;   /* State change report count */
	struct address6_list inm6_allow; /* addresses to report in ALLOW */
	struct address6_list inm6_block; /* addresses to report in BLOCK */
	struct address6_list inm6_query_srcs; /* group and source specific query */
};

#define MULTI6_OTHERMEMBER		1
#define MULTI6_IREPORTEDLAST		2

#if defined(_KERNEL)

/*
 * Structure used by macros below to remember position when stepping through
 * all of the in6_multi records.
 */
struct in6_multistep {
	struct ifnet *i6_if;
	struct ifnet *i6_lastif;
	struct in6_multi *i6_inm;
};

/*
 * Macro for looking up the in6_multi record
 * for a given IPv6 multicast address on a given interface.
 * If no matching record is found, "inm" returns NULL.
 */
#define IN6_LOOKUP_MULTI(addr, ifp, inm) \
	/* struct in6_addr addr; */ \
	/* struct ifnet *ifp; */ \
	/* struct in6_multi *inm; */ \
{ \
	IF6MULTI_LOCK(ifp); \
	for ((inm) = ifp->if_multiaddrs6.lh_first; \
	    (inm) != NULL && !SAME_ADDR6((inm)->inm6_addr, (addr)); \
	     (inm) = inm->inm6_entry.le_next) \
		 continue; \
	IF6MULTI_UNLOCK(ifp); \
}

#define IN6_LOOKUP_MULTI_NOLOCK(addr, ifp, inm) \
	/* struct in6_addr addr; */ \
	/* struct ifnet *ifp; */ \
	/* struct in6_multi *inm; */ \
{ \
	for ((inm) = ifp->if_multiaddrs6.lh_first; \
	    (inm) != NULL && !SAME_ADDR6((inm)->inm6_addr, (addr)); \
	     (inm) = inm->inm6_entry.le_next) \
		 continue; \
}

#define UNLOCK_LAST_MULTI6(step) \
       if((step).i6_lastif) IF6MULTI_UNLOCK_RECURSIVE((step).i6_lastif)


/*
 * Macro for looking up the in_multi record for a given IP multicast address
 * on a given interface.  If no matching record is found or if source is
 * blocked, "inm" returns NULL.
 */
#define IN6_LOOKUP_SOURCE_MULTI(saddr, addr, ifp, inm)                      \
        /* struct in6_addr       saddr;  */                                 \
        /* struct in6_addr       addr;   */                                 \
        /* struct ifnet         *ifp;   */                                 \
        /* struct in6_multi      *inm;   */                                 \
{                                                                          \
        IFMULTI_LOCK(ifp);                                                 \
        for ((inm) = ifp->if_multiaddrs6.lh_first;			   \
	     (inm) != NULL && !SAME_ADDR6((inm)->inm6_addr, (addr));       \
             (inm) = inm->inm6_entry.le_next);                              \
       	if (inm != NULL) {                                                 \
             IN6_LOOKUP_SOURCE_NOLOCK(inm,saddr);                        \
      	}                                                                  \
        IFMULTI_UNLOCK(ifp);                                               \
}

#define IN6_LOOKUP_SOURCE_NOLOCK(inm, saddr)                                \
        /* struct in6_multi      *inm;   */                                 \
        /* struct in6_addr       saddr;  */                                 \
{                                                                          \
        int index;                                                         \
        struct filter6_list *fl = &(inm->inm6_fl);                           \
                                                                           \
        if (fl->fl_mode == INM_EXCLUDE) {                                  \
                for (index=0; index<fl->num_src; index++)                  \
                        if (SAME_ADDR6(fl->fl6_src[index], saddr)) {    \
                                inm = NULL;                                \
                                break;                                     \
                        }                                                  \
        } else if (fl->fl_mode == INM_INCLUDE) {                           \
                for (index=0; index<fl->num_src; index++)                  \
                        if (SAME_ADDR6(fl->fl6_src[index], saddr))      \
                                break;                                     \
                if (index == fl->num_src)                                  \
                        inm = NULL;                                        \
        }                                                                  \
}
/*
 * Macro to step through all of the in6_multi records, one at a time.
 * The current position is remembered in "step", which the caller must
 * provide.  IN6_FIRST_MULTI(), below, must be called to initialize "step"
 * and get the first record.  Both macros return a NULL "inm" when there
 * are no remaining records.
 */
#define IN6_NEXT_MULTI(step, inm) \
	/* struct in6_multistep  step; */ \
	/* struct in6_multi *inm; */ \
{ \
	if (((inm) = (step).i6_inm) != NULL) \
		(step).i6_inm = (inm)->inm6_entry.le_next; \
	else \
		while ((step).i6_if != NULL) { \
			UNLOCK_LAST_MULTI6(step); \
			IF6MULTI_LOCK_RECURSIVE((step).i6_if); \
			(inm) = (step).i6_if->if_multiaddrs6.lh_first; \
			(step).i6_lastif = (step).i6_if; \
			(step).i6_if = (step).i6_if->if_next; \
			if ((inm) != NULL) { \
				(step).i6_inm = (inm)->inm6_entry.le_next; \
				break; \
			} \
		} \
}

#define IN6_FIRST_MULTI(step, inm) \
	/* struct in6_multistep step; */ \
	/* struct in6_multi *inm; */ \
{ \
	(step).i6_if = ifnet; \
	(step).i6_inm = NULL; \
	(step).i6_lastif = NULL; \
	IN6_NEXT_MULTI((step), (inm)); \
}

/*
 * Macro to find the same sinfo structure for the given sourceaddr.
 * Currently just matches one sourceaddr due to performance issues.
 */
#define IN6_LOOKUP_SOURCE_RECORD_NOLOCK(inm6, sinfo6, mode, sourceaddr6)      \
        /* struct in6_multi      *inm;   */                                 \
        /* struct source6_info   *sinfo; */                                 \
        /* int                  mode;   */                                 \
        /* struct in6_addr       sourceaddr; */                             \
{                                                                          \
        for((sinfo6) = (inm6)->inm6_ui; (sinfo6) != NULL;                     \
             (sinfo6) = (sinfo6)->si6_next) {                                 \
                if ((sinfo6->num_src == 1) &&                            \
                    (SAME_ADDR6(sinfo6->si6_src[0] , sourceaddr6)) &&     \
                    (sinfo6->si_mode == mode)) {                           \
                        break;                                             \
                }                                                          \
        }                                                                  \
}
#define IN6ADDR_ALLOC(addrp, size, max6_src)                                   \
        /* struct in6_addr *addrp; */                                         \
        /* ushort size; */                                                   \
        /* ushort max_src; */                                                \
{                                                                            \
        NET_MALLOC(addrp, struct in6_addr *, (sizeof(struct in6_addr)) * size, \
                M_IPMADDR, M_NOWAIT);                                        \
        if (addrp == NULL)                                                   \
                return;                                                      \
        bzero((caddr_t)addrp, sizeof(struct in6_addr)*size);                  \
        max6_src = size;                                                      \
}

#define IN6ADDR_ALLOC_RC(addrp, size, max6_src)                              \
        /* struct in6_addr *addrp; */                                        \
        /* ushort size; */                                                   \
        /* ushort max_src; */                                                \
{                                                                            \
        NET_MALLOC(addrp, struct in6_addr *, (sizeof(struct in6_addr)) * size, \
                M_IPMADDR, M_NOWAIT);                                        \
        if (addrp == NULL)                                                   \
                return NULL;                                                 \
        bzero((caddr_t)addrp, sizeof(struct in6_addr)*size);                 \
        max6_src = size;                                                     \
}

#define IN6ADDR_REALLOC(addrp, size, max_src)                                 \
        /* struct in6_addr *addrp; */                                         \
        /* ushort size; */                                                   \
        /* ushort max_src; */                                                \
{                                                                            \
        struct in6_addr *readdrp;                                             \
        NET_MALLOC(readdrp, struct in6_addr *,                                \
                (sizeof(struct in6_addr))*(size+max_src), M_IPMADDR, M_NOWAIT); \
        if (readdrp == NULL)                                                 \
                return;                                                      \
        bzero((caddr_t)readdrp, sizeof(struct in6_addr)*(size+max_src));      \
        bcopy((caddr_t)addrp, (caddr_t)readdrp,                              \
                sizeof(struct in6_addr)*max_src);                             \
        max_src += size;                                                     \
        NET_FREE(addrp, M_IPMADDR);                                          \
        addrp = readdrp;                                                     \
}

#define IN6ADDR_REALLOC_RC(addrp, size, max_src)                             \
        /* struct in6_addr *addrp; */                                        \
        /* ushort size; */                                                   \
        /* ushort max_src; */                                                \
{                                                                            \
        struct in6_addr *readdrp;                                            \
        NET_MALLOC(readdrp, struct in6_addr *,                               \
                (sizeof(struct in6_addr))*(size+max_src), M_IPMADDR, M_NOWAIT); \
        if (readdrp == NULL)                                                 \
                return NULL;                                                 \
        bzero((caddr_t)readdrp, sizeof(struct in6_addr)*(size+max_src));     \
        bcopy((caddr_t)addrp, (caddr_t)readdrp,                              \
                sizeof(struct in6_addr)*max_src);                            \
        max_src += size;                                                     \
        NET_FREE(addrp, M_IPMADDR);                                          \
        addrp = readdrp;                                                     \
}

#define S6INFO_COPY_RC(sinfo6, sinfo6_new, inm6)                             \
        /* struct source6_info *sinfo6 */                                    \
        /* struct source6_info *sinfo6_new */                                \
        /* struct in6_multi *inm6 */                                         \
{                                                                            \
        NET_MALLOC(sinfo6_new, struct source6_info *,                        \
                sizeof(*sinfo6_new), M_IPMADDR, M_NOWAIT);                   \
        IN6ADDR_ALLOC_RC(sinfo6_new->si6_src, sinfo6->max_src,               \
                sinfo6_new->max_src);                                        \
        if ((sinfo6_new == NULL) || (sinfo6_new->si6_src == NULL))           \
                return NULL;                                                 \
        bcopy((caddr_t)sinfo6->si6_src, (caddr_t)sinfo6_new->si6_src,        \
                sizeof(struct in6_addr)*sinfo6->num_src);                    \
        --sinfo6->refcount;                                                  \
        sinfo6_new->si_mode = sinfo6->si_mode;                               \
        sinfo6_new->num_src = sinfo6->num_src;                               \
        sinfo6_new->refcount = 1;                                            \
        sinfo6_new->si6_next = inm6->inm6_ui;                                \
        inm6->inm6_ui = sinfo6_new;                                          \
}


#define ADDR6INFO_ALLOC(addrp, size, max_src)                             \
        /* struct addr6_info *addrp; */                                \
        /* ushort size; */                                               \
        /* ushort max_src; */                                            \
{                                                                        \
        NET_MALLOC(addrp, struct addr6_info *,                            \
                (sizeof(struct addr6_info)) * size, M_IPMADDR, M_NOWAIT); \
        if (addrp == NULL)                                               \
                return;                                                  \
        bzero((caddr_t)addrp, sizeof(struct addr6_info)*size);            \
        max_src = size;                                                  \
}

#define ADDR6INFO_ALLOC_RC(addrp, size, max_src)                          \
        /* struct addr6_info *addrp; */                                   \
        /* ushort size; */                                                \
        /* ushort max_src; */                                             \
{                                                                         \
        NET_MALLOC(addrp, struct addr6_info *,                            \
                (sizeof(struct addr6_info)) * size, M_IPMADDR, M_NOWAIT); \
        if (addrp == NULL)                                                \
                return NULL;                                              \
        bzero((caddr_t)addrp, sizeof(struct addr6_info)*size);            \
        max_src = size;                                                   \
}

#define ADDR6INFO_REALLOC(addrp, size, max_src)                           \
        /* struct addr6_info *addrp; */                                \
        /* ushort size; */                                               \
        /* ushort max_src; */                                            \
{                                                                        \
        struct addr6_info *readdrp;                                       \
        NET_MALLOC(readdrp, struct addr6_info *,                          \
                (sizeof(struct addr6_info))*(size+max_src),               \
                        M_IPMADDR, M_NOWAIT);                            \
        if (readdrp == NULL)                                             \
                return;                                                  \
        bzero((caddr_t)readdrp, sizeof(struct addr6_info)*(size+max_src)); \
        bcopy((caddr_t)addrp, (caddr_t)readdrp,                          \
                sizeof(struct addr6_info)*max_src);                       \
        max_src += size;                                                 \
        NET_FREE(addrp, M_IPMADDR);                                      \
        addrp = readdrp;                                                 \
}

#define ADDR6INFO_REALLOC_RC(addrp, size, max_src)                       \
        /* struct addr6_info *addrp; */                                  \
        /* ushort size; */                                               \
        /* ushort max_src; */                                            \
{                                                                        \
        struct addr6_info *readdrp;                                      \
        NET_MALLOC(readdrp, struct addr6_info *,                         \
                (sizeof(struct addr6_info))*(size+max_src),              \
                        M_IPMADDR, M_NOWAIT);                            \
        if (readdrp == NULL)                                             \
                return NULL;                                             \
        bzero((caddr_t)readdrp, sizeof(struct addr6_info)*(size+max_src)); \
        bcopy((caddr_t)addrp, (caddr_t)readdrp,                          \
                sizeof(struct addr6_info)*max_src);                      \
        max_src += size;                                                 \
        NET_FREE(addrp, M_IPMADDR);                                      \
        addrp = readdrp;                                                 \
}

struct router6_info {
	struct ifnet *ifp;
	char   type; /* type of router which is querier on this interface */
	char   robustness;
	short  v1querier; /* # of slow timeouts since last v1 query */
	short  queriertime;   /* Querier present interval */
	short	iftimer;   /* Interface timer to respond to general queries */
	struct router6_info *next;
};


struct source6_info *in6_changemulti_nolock(struct in6_multi *,
struct source6_info *, char, struct in6_addr, struct ifnet *);
struct source6_info *in6_changemulti(struct in6_multi *,
struct source6_info *, char, struct in6_addr);
struct in6_multi *in6_addmulti_source(struct ifnet *, 
                                      struct in6_multi *,
                                      struct source6_info **,
                                      char,
                                      struct in6_addr,
                                      struct in6_addr,
                                      struct inpcb *);
struct in6_multi *in6_addmulti_sources(struct ifnet *, 
                                       struct in6_multi *,
                                       struct source6_info **,
                                       char,
                                       struct sockaddr_storage *,
                                       int,
                                       struct sockaddr_storage *,
                                       struct inpcb *);
struct source6_info *in6_changemulti_sources_nolock(struct in6_multi *,
struct source6_info *, char, int, struct sockaddr_storage *, struct ifnet *);
struct in6_multi *in6_addmulti_nolock(struct in6_addr*, struct ifnet *, int, struct inpcb *);
void in6_change_filter(struct in6_multi *);
void in6_del_addrlist(struct in6_multi *, struct source6_info *);
void in6_change_addrlist(struct in6_multi *, struct in6_addr, int, int);
void mergefl6(struct in6_multi *, struct filter6_list *,
struct address6_list *, struct address6_list *);
void merge6report(struct in6_multi *, struct address6_list *,
struct address6_list *);
int in6_delmulti_source(struct in6_multi *, struct source6_info *);
void inm6_scrub(struct in6_multi *);
#endif


/* hash chain structure ot enocde the ipv6 anycast addresses
 * in a linked list as well as an array of hashed entries
 */

struct in6anycast_hash {
        struct in6anycast_hash       *next;
        struct in6anycast_hash       *prev;
};

#define ia6hashtoanycast(hp)         \
        (struct in6_anycast *)((char *)(hp) - offsetof(struct in6_anycast, ia_hash))
#define in6anycasttohash(ia)        (&(ia->ia_hash))
#define IN6ANYADDR_HASHSZ            29

#define IN6ANYADDR_HASH(addr) ((addr) % IN6ANYADDR_HASHSZ)

struct in6anycast_hash_table {
        struct in6anycast_hash    head;
};

extern struct in6anycast_hash_table in6anycast_hash_table[IN6ANYADDR_HASHSZ];

struct aligned_in6anycast_lock {
	simple_lock_data_t	_l; 
	char			dummy[NET_CACHELINESIZE - sizeof(simple_lock_data_t)];
};

/* Hash table chain head lock */
#if     defined(_KERNEL)
extern  struct  aligned_in6anycast_lock      in6anycast_hashchn_lock[IN6ANYADDR_HASHSZ];
#endif


/*
 * Anycast address structure.
 */

struct in6_anycast {
#ifdef _KERNEL
    LIST_ENTRY(in6_anycast) ina6_list;  /* list glue */
#endif
    struct  in6_addr ina6_addr; /* IPv6 anycast address */
    u_int   ina6_refcount;      /* reference count */
    u_int   ina6_flags;         /* flags */
    struct  in6anycast_hash ia_hash;  /* hash links */
};
#define IP6ANY_VALID        1       /* valid entry */
#define IP6ANY_ROUTER       2       /* router anycast */
#define IP6ANY_ALLWAYS      3       /* allways get it! */

#endif

