/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* bos72Q src/bos/kernext/inet/in_var.h 1.29.5.3                          */
/*                                                                        */
/* Licensed Materials - Property of IBM                                   */
/*                                                                        */
/* COPYRIGHT International Business Machines Corp. 1988,2019              */
/* 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                                                     */
/* @(#)50       1.29.5.3  src/bos/kernext/inet/in_var.h, sockinc, bos72Q, q2019_13A4 2/6/19 00:43:31 */
/*
 *   COMPONENT_NAME: SYSXINET
 *
 *   FUNCTIONS: IA_SIN
 *		IFP_TO_IA
 *		INADDR_TO_IFP
 *		INIFADDR_LOCKINIT
 *		INIFADDR_READ_LOCK
 *		INIFADDR_UNLOCK
 *		INIFADDR_WRITE_LOCK
 *		IN_FIRST_MULTI
 *		IN_LOOKUP_MULTI
 *		IN_LOOKUP_MULTI_NOLOCK
 *		IN_NEXT_MULTI
 *		UNLOCK_LAST_MULTI
 *		
 *
 *   ORIGINS: 26,27,85,89,127,196
 *
 *
 *   (C) COPYRIGHT International Business Machines Corp. 1988,1997
 *   All Rights Reserved
 *   Licensed Materials - Property of IBM
 *   US Government Users Restricted Rights - Use, duplication or
 *   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
 */

/*
 * 
 * (c) Copyright 1991, OPEN SOFTWARE FOUNDATION, INC.
 * ALL RIGHTS RESERVED
 * 
 */
/*
 * OSF/1 1.2
 */
/*
 * Copyright (c) 1985, 1986 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted provided
 * that: (1) source distributions retain this entire copyright notice and
 * comment, and (2) distributions including binaries display the following
 * acknowledgement:  ``This product includes software developed by the
 * University of California, Berkeley and its contributors'' in the
 * documentation or other materials provided with the distribution and in
 * all advertising materials mentioning features or use of this software.
 * 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 *	Base:	in_var.h	7.4 (Berkeley) 4/22/89
 *	Merged:	in_var.h	7.6 (Berkeley) 6/28/90
 */

#ifndef _IN_VAR_H_
#define _IN_VAR_H_

#include <net/net_rules.h>

#include <sys/corralid.h>

#ifdef __cplusplus
extern "C" {
#endif

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

struct inifaddr_hash {
	struct inifaddr_hash *next;
	struct inifaddr_hash *prev;
};

#define iahashtoinifaddr(hp)         \
        (struct in_ifaddr *)((char *)(hp) - offsetof(struct in_ifaddr, ia_hash))
#define inifaddrtohash(ia)        (&(ia->ia_hash))
#define INIFADDR_HASHSZ            29

#define INIFADDR_HASH(addr) ((addr) % INIFADDR_HASHSZ)

struct inifaddr_hash_table {
	struct inifaddr_hash head;
};

extern struct inifaddr_hash_table inifaddr_hash_table[INIFADDR_HASHSZ];

/* Hash table chain head lock */
#if     defined(_KERNEL)
extern struct rw_lock *inifaddr_hashchn_lock[INIFADDR_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_pbc.h (because of build breaks
 * encountered when included through net_globals.h).
 */

/*
 * Interface address, Internet version.  One of these structures
 * is allocated for each interface with an Internet address.
 * The ifaddr structure contains the protocol-independent part
 * of the structure and is assumed to be first.
 */
struct in_ifaddr {
	struct ifaddr ia_ifa;		/* protocol-independent info */
#define	ia_ifp		ia_ifa.ifa_ifp
#define ia_flags	ia_ifa.ifa_flags
	/* ia_{,sub}net{,mask} in host order */
	u_long	ia_net;			/* network number of interface */
	u_long	ia_netmask;		/* mask of net part */
	u_long	ia_subnet;		/* subnet number, including net */
	u_long	ia_subnetmask;		/* mask of subnet part */
	struct in_addr ia_netbroadcast; /* to recognize net broadcasts */
	struct in_ifaddr *ia_next;	/* next in list of internet addresses */
	struct sockaddr_in ia_addr;	/* reserve space for interface name */
	struct sockaddr_in ia_dstaddr; /* reserve space for broadcast addr */
#define	ia_broadaddr	ia_dstaddr
	struct sockaddr_in ia_sockmask; /* reserve space for general netmask */
	struct inifaddr_hash ia_hash;  /* hash links                   */
	cid_t	ia_kcid;		/* kernel corral id */
	int_rule_t	 * if_rule;	/* MLS interface rule */
};

struct in_aliasreq {
	char	ifra_name[IFNAMSIZ];		/* if name, e.g. "en0" */
	struct sockaddr_in ifra_addr;
	struct sockaddr_in ifra_broadaddr;
#define ifra_dstaddr ifra_broadaddr
	struct sockaddr_in ifra_mask;
};
#ifdef PHABRE1

struct in_clustreq {
	char    ifra_name[IFNAMSIZ];            /* if name, e.g. "en0" */
	struct sockaddr_in ifra_addr;
	struct sockaddr_in ifra_broadaddr;
#define ifra_dstaddr ifra_broadaddr
	struct sockaddr_in ifra_mask;
	u_short            ifra_flags;
};

#endif /* PHABRE1 */
/*
 * Given a pointer to an in_ifaddr (ifaddr),
 * return a pointer to the addr as a sockaddr_in.
 */
#define	IA_SIN(ia) (&(((struct in_ifaddr *)(ia))->ia_addr))

#ifdef	_KERNEL
#define INIFADDR_HASHCHNHEAD_LOCKINIT(index) \
	RW_LOCKINIT(inifaddr_hashchn_lock[index], 2*NET_CACHELINESIZE, M_LOCKF, M_WAITOK, LOCK_ALLOC_PIN, \
	INIFADDR_LOCK_FAMILY, -1);
#define INIFADDR_HASHCHNHEAD_LOCK_DECL()	int	_inifl_h, _inifrl_h;
#define INIFADDR_HASHCHNHEAD_WRITE_LOCK(index) RW_WRITE_LOCK(inifaddr_hashchn_lock[index], _inifl_h, PL_IMP)
#define INIFADDR_HASHCHNHEAD_WRITE_UNLOCK(index) RW_WRITE_UNLOCK(inifaddr_hashchn_lock[index], _inifl_h)
#define INIFADDR_HASHCHNHEAD_READ_LOCK(index) \
	RW_READ_LOCK(inifaddr_hashchn_lock[index], _inifl_h, PL_IMP, _inifrl_h)
#define INIFADDR_HASHCHNHEAD_READ_UNLOCK(index) RW_READ_UNLOCK(inifaddr_hashchn_lock[index], _inifrl_h)
#endif


#ifdef	_KERNEL
extern DRW_lock *inifaddr_lock;
#define INIFADDR_LOCKINIT() \
	do { \
		NET_MALLOC(inifaddr_lock, DRW_lock *, sizeof(DRW_lock), \
				M_LOCKF, M_WAITOK); \
		lock_alloc(inifaddr_lock, LOCK_ALLOC_PIN, INIFADDR_LOCK_FAMILY, -1); \
		drw_lock_init(inifaddr_lock); \
	} while (0)

#define INIFADDR_LOCK_DECL()	int	_inifl, _inifrl;

#define INIFADDR_WRITE_LOCK() \
	do { \
		_inifl = i_disable(PL_IMP); \
		drw_lock_write(inifaddr_lock); \
	} while (0)

#define INIFADDR_WRITE_UNLOCK() \
	do { \
		drw_lock_done(inifaddr_lock); \
		i_enable(_inifl); \
	} while (0)

#define INIFADDR_READ_LOCK() \
	do { \
		_inifrl = i_disable(PL_IMP); \
		drw_lock_read(inifaddr_lock); \
	} while (0)

#define INIFADDR_READ_UNLOCK() \
	do { \
		drw_lock_done(inifaddr_lock); \
		i_enable(_inifrl); \
	} while (0)


/*----------------------------------
 * Define 629937
 *
 * Convert an INIFADDR_WRITE_LOCK to a READ lock, and
 * then restore it to a WRITE lock.  You must restore the
 * lock back -- not simple call READ_UNLOCK, or you risk
 * an incorrect priority. 
 */
#define INIFADDR_WRITE_TO_READ_LOCK() \
	drw_lock_write_to_read(inifaddr_lock)

#define INIFADDR_READ_TO_WRITE_LOCK(_ret_val) \
	(_ret_val) = drw_lock_read_to_write(inifaddr_lock)

#define INIFADDR_WRITE_LOCK_NO_DISABLE() \
		drw_lock_write(inifaddr_lock)

extern struct domain inetdomain;
extern CONST struct protosw inetsw[];
extern long	inetprintfs;
extern long	ipforwarding;
extern CONST	struct sockaddr_in in_zeroaddr;
extern CONST	struct sockaddr_in6 in6_zeroaddr;
extern struct in_ifaddr *in_ifaddr;
extern struct ifqueue ipintrq[NETMAXCPU]; 	/* ip packet input queue */

#endif
#ifdef IP_MULTICAST
/*
 * Internet multicast address structure.  There is one of these for each IP
 * multicast group to which this host belongs on a given network interface.
 * They are kept in a linked list, rooted at the interface (struct ifnet)
 * structure.
 */

#define INM_INIT_SOURCE 16 /* No. of source addresses per socket per group */
#define INM_INIT_ADDR_LIST 64 /* No. of blocked/included addresses per group */
#define INM_INIT_FLT_LIST 128 /* No. of addresses in filter list per group */
#define SRC_ADD 1	/* Option for adding to the address list */
#define SRC_DEL 0	/* Option for deleting from the address list */
#define INM_INCLUDE 1  /* Should be same value as MODE_IS_INCLUDE in igmp.h */
#define INM_EXCLUDE 2  /* Should be same value as MODE_IS_EXCLUDE in igmp.h */

struct source_info {
	char	si_mode;	/* filter mode */
	ushort	num_src;	/* No. of source addresses in list */
	ushort	max_src;	/* Max source addresses that can fit */
	ushort	refcount;
	struct in_addr *si_src;	/* Source list */
	struct source_info *si_next;
};

/* Filter list per multicast group */
struct filter_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 in_addr *fl_src;	/* Source list */
};

/* Include/Exclude addresses per group */
struct addr_info {
	struct in_addr addr; /* Address list */
	ushort	count; /* Refcount/pending report count */
};

struct address_list {
	ushort	num_src;	/* Number of sources in the list */
	ushort	max_src;	/* Max source addresses that can fit */
	struct addr_info *al_ai;
};

struct in_multi {
	struct in_addr inm_addr;	/* IP multicast address */
	struct ifnet *inm_ifp;	/* back pointer to ifnet */
	u_int		  inm_refcount;	/* no. membership claims by sockets */
	ushort		  exc_count; /* no. sockets in exclude mode */
	ushort		  sicount; /* no. sockets having source info */
	u_int		  inm_state;	/* state of the membership */
/* For IGMPv3, inm_timer is used for retransmission of reports from 'change
 * of interface state'. inm_timer2 will be used for scheduling reports on
 * reception of a group specific query
 */
	u_int		  inm_timer;	/* IGMP membership report timer */
	u_int		  inm_timer2;	/* IGMPv3 membership report timer */
	struct in_multi *inm_next;	/* ptr to next multicast address */
	struct router_info *inm_rti;	/* router info */
	struct source_info *inm_ui;	/* Source Address info */
	struct address_list inm_exc_list; /* list of excluded addresses */
	struct address_list inm_inc_list; /* list of included addresses */
	struct filter_list inm_fl;	/* Consolidated source list */
	char	smode;	/* State change mode */
	ushort		state_count;   /* State change report count */
	struct address_list inm_allow; /* addresses to report in ALLOW */
	struct address_list inm_block; /* addresses to report in BLOCK */
	struct address_list inm_query_srcs; /* group and source specific query */
	cid_t im_kcid;			    /* kcid of the WPAR using this mcast addr */
};

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

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

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

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

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

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

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

#ifdef _KERNEL
/*
 * Macro for finding the interface (ifnet structure) corresponding to one
 * of our IP addresses.
 */
#define INADDR_TO_IFP(addr, ifp)                                             \
        /* struct in_addr addr; */                                           \
        /* struct ifnet  *ifp;  */                                           \
{                                                                            \
        register struct in_ifaddr *ia;                                       \
        struct inifaddr_hash *hp;                                            \
        struct inifaddr_hash_table *tablep;                                  \
        int index;                                                           \
        INIFADDR_HASHCHNHEAD_LOCK_DECL()                                     \
	ifp = NULL;                                                              \
                                                                             \
        index = INIFADDR_HASH((addr).s_addr);                                \
        INIFADDR_HASHCHNHEAD_READ_LOCK(index);                               \
                                                                             \
        tablep = &inifaddr_hash_table[index];                                \
        for (hp = tablep->head.next; hp != &(tablep->head); hp = hp->next) { \
                ia = iahashtoinifaddr(hp);                                   \
                if (IA_SIN(ia)->sin_addr.s_addr == (addr).s_addr){           \
        		(ifp) = ia->ia_ifp;                                          \
                        break;                                               \
		}                                                                    \
        }                                                                    \
                                                                             \
        INIFADDR_HASHCHNHEAD_READ_UNLOCK(index);                             \
                                                                             \
}

/*
 * Macro for finding the internet address structure (in_ifaddr) corresponding
 * to a given interface (ifnet structure).
 */
#define IFP_TO_IA(ifp, ia)                                                \
        /* struct ifnet     *ifp; */                                      \
        /* struct in_ifaddr *ia;  */                                      \
{                                                                         \
       struct inifaddr_hash *hp, *hphead;                                 \
       int index;                                                         \
       INIFADDR_HASHCHNHEAD_LOCK_DECL()                                   \
							                                    		  \
       ia = NULL;                                                         \
       for(index = 0; index < INIFADDR_HASHSZ; index++) {                 \
             if (inifaddr_hash_table[index].head.next !=                  \
                  &(inifaddr_hash_table[index].head)) {                   \
                    INIFADDR_HASHCHNHEAD_READ_LOCK(index);                \
                    hphead = &(inifaddr_hash_table[index].head);          \
                    hp = hphead->next;                                    \
                    if ((hp != hphead) && hp) {                           \
                             for(; hp != hphead; hp = hp->next) {         \
                                    (ia) = iahashtoinifaddr(hp);          \
                                    if ((ia)->ia_ifp == (ifp)) {          \
                                         INIFADDR_HASHCHNHEAD_READ_UNLOCK(index);   \
                                         break;                           \
                                    }                                     \
                              } /* hash chain for loop */                 \
                    }                                                     \
		    if ((ia) && (ia)->ia_ifp == (ifp))                            \
			     break;			                                		  \
                    INIFADDR_HASHCHNHEAD_READ_UNLOCK(index);              \
               } /* if test for inifaddrs in this chain */                \
       } /* index for loop */                                             \
       if ((ia) && (ia)->ia_ifp != (ifp))                                 \
       		ia = 0;                                                       \
}

/*
 * This information should be part of the ifnet structure but we don't wish
 * to change that - as it might break a number of things
 */

struct router_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	v2querier; /* # of slow timeouts since last v2 query */
	short	queriertime;   /* Querier present interval */
	short	iftimer;   /* Interface timer to respond to general queries */
	struct router_info *next;
};

/*
 * Structure used by macros below to remember position when stepping through
 * all of the in_multi records.
 */
struct in_multistep {
	struct ifnet *i_if;
	struct ifnet *i_lastif;
	struct in_multi *i_inm;
};

/*
 * Macro for looking up the in_multi record for a given IP multicast address
 * on a given interface.  If no matching record is found, "inm" returns NULL.
 */
#define IN_LOOKUP_MULTI(addr, ifp, inm, kcid)			            \
	/* struct in_addr  addr; */					    \
	/* struct ifnet    *ifp; */					    \
	/* struct in_multi *inm; */					    \
        /* cid_t kcid; */                                                   \
{								            \
	    IFMULTI_LOCK(ifp);						    \
	    for ((inm) = ifp->if_multiaddrs;		    \
                 ((inm) != NULL && !(((inm)->inm_addr.s_addr == (addr).s_addr) \
                  && ((inm)->im_kcid == kcid)));                            \
		 (inm) = inm->inm_next);				    \
	    IFMULTI_UNLOCK(ifp);					    \
}

#define IN_LOOKUP_MULTI_NOLOCK(addr, ifp, inm, kcid)	   		    \
	/* struct in_addr  addr; */					    \
	/* struct ifnet    *ifp; */					    \
	/* struct in_multi *inm; */					    \
        /* cid_t kcid; */                                                   \
{								            \
	    for ((inm) = ifp->if_multiaddrs;            		    \
                 ((inm) != NULL && !(((inm)->inm_addr.s_addr == (addr).s_addr) \
                  && ((inm)->im_kcid == kcid)));                              \
		 (inm) = inm->inm_next);				    \
}

/*
 * Macro for looking up the in_multi record for a given IP multicast address
 * and kcid on a given interface.  If no matching record is found,
 * "inm" returns NULL. We are searching for the same mulitcast address with
 * different kcid. This indicates there is another listener on same box
 * from different WPAR / Global WPAR is listening for this address.
 */
#define IN_LOOKUP_MULTI_WPAR(addr, ifp, inm, kcid)                          \
        /* struct in_addr  addr; */                                         \
        /* struct ifnet    *ifp; */                                         \
        /* struct in_multi *inm; */                                         \
        /* cid_t kcid; */                                                   \
{                                                                           \
            IFMULTI_LOCK(ifp);                                              \
            for ((inm) = ifp->if_multiaddrs;                                \
                 (inm) != NULL && !(((inm)->inm_addr.s_addr == (addr).s_addr) \
                  && ((inm)->im_kcid != kcid));                                 \
                 (inm) = inm->inm_next);                                    \
            IFMULTI_UNLOCK(ifp);                                            \
}


#define IN_LOOKUP_MULTI_WPAR_NOLOCK(addr, ifp, inm, kcid)                   \
        /* struct in_addr  addr; */                                         \
        /* struct ifnet    *ifp; */                                         \
        /* struct in_multi *inm; */                                         \
        /* cid_t kcid; */                                                   \
{                                                                           \
            for ((inm) = ifp->if_multiaddrs;                                \
                 (inm) != NULL && !(((inm)->inm_addr.s_addr == (addr).s_addr) \
                  && ((inm)->im_kcid != kcid));                                 \
                 (inm) = inm->inm_next);                                    \
}

/*
 * 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 IN_LOOKUP_SOURCE_MULTI(saddr, addr, ifp, inm)                      \
	/* struct in_addr	saddr;	*/                                 \
	/* struct in_addr	addr;	*/                                 \
	/* struct ifnet		*ifp;	*/                                 \
	/* struct in_multi	*inm;	*/                                 \
{                                                                          \
	IFMULTI_LOCK(ifp);                                                 \
	for ((inm) = ifp->if_multiaddrs;                                   \
	       (inm) != NULL && (inm)->inm_addr.s_addr != (addr).s_addr;   \
		 (inm) = inm->inm_next);                                   \
	if (inm != NULL) {                                                 \
		IN_LOOKUP_SOURCE_NOLOCK(inm,saddr);                        \
	}                                                                  \
	IFMULTI_UNLOCK(ifp);                                               \
}

#define IN_LOOKUP_SOURCE_NOLOCK(inm, saddr)                                \
	/* struct in_multi	*inm;	*/                                 \
	/* struct in_addr	saddr;	*/                                 \
{                                                                          \
	int index;                                                         \
	struct filter_list *fl = &(inm->inm_fl);                           \
                                                                           \
	if (fl->fl_mode == INM_EXCLUDE) {                                  \
		for (index=0; index<fl->num_src; index++)                  \
			if (fl->fl_src[index].s_addr == saddr.s_addr) {    \
				inm = NULL;                                \
				break;                                     \
			}                                                  \
	} else if (fl->fl_mode == INM_INCLUDE) {                           \
		for (index=0; index<fl->num_src; index++)                  \
			if (fl->fl_src[index].s_addr == saddr.s_addr)      \
				break;                                     \
		if (index == fl->num_src)                                  \
			inm = NULL;                                        \
	}                                                                  \
}
/*
 * Macro to find the same sinfo structure for the given sourceaddr.
 * Currently just matches one sourceaddr due to performance issues.
 */
#define IN_LOOKUP_SOURCE_RECORD_NOLOCK(inm, sinfo, mode, sourceaddr)      \
	/* struct in_multi	*inm;	*/                                 \
	/* struct source_info	*sinfo;	*/                                 \
	/* int			mode;	*/                                 \
	/* struct in_addr	sourceaddr; */                             \
{                                                                          \
	for((sinfo) = (inm)->inm_ui; (sinfo) != NULL;                     \
	     (sinfo) = (sinfo)->si_next) {                                 \
		if ((sinfo->num_src == 1) &&                            \
		    (sinfo->si_src[0].s_addr == sourceaddr.s_addr) &&     \
		    (sinfo->si_mode == mode)) {                           \
			break;                                             \
		}                                                          \
	}                                                                  \
}

#define SINFO_COPY_RC(sinfo, sinfo_new, inm)                               \
	/* struct source_info *sinfo */                                    \
	/* struct source_info *sinfo_new */                                \
	/* struct in_multi *inm */                                         \
{                                                                          \
	NET_MALLOC(sinfo_new, struct source_info *,                        \
		sizeof(*sinfo_new), M_IPMADDR, M_NOWAIT);                  \
	if (sinfo_new == NULL)                                             \
		return NULL;                                               \
	INADDR_ALLOC_RC(sinfo_new->si_src, sinfo->max_src,                 \
		sinfo_new->max_src);                                       \
	if (sinfo_new->si_src == NULL) {                                   \
		NET_FREE(sinfo_new, M_IPMADDR);                            \
		return NULL;                                               \
	}                                                                  \
	bcopy((caddr_t)sinfo->si_src, (caddr_t)sinfo_new->si_src,          \
		sizeof(struct in_addr)*sinfo->num_src);                    \
	--sinfo->refcount;                                                 \
	sinfo_new->si_mode = sinfo->si_mode;                               \
	sinfo_new->num_src = sinfo->num_src;                               \
	sinfo_new->refcount = 1;                                           \
	sinfo_new->si_next = inm->inm_ui;                                  \
	inm->inm_ui = sinfo_new;                                           \
}

#define UNLOCK_LAST_MULTI(step)						\
       if((step).i_lastif) IFMULTI_UNLOCK_RECURSIVE((step).i_lastif)

/*
 * Macro to step through all of the in_multi records, one at a time.
 * The current position is remembered in "step", which the caller must
 * provide.  IN_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 IN_NEXT_MULTI(step, inm)					\
	/* struct in_multistep  step; */				\
	/* struct in_multi     *inm;  */				\
{									\
	if (((inm) = (step).i_inm) != NULL) {				\
		(step).i_inm = (inm)->inm_next;				\
	}								\
	else while ((step).i_if != NULL) {				\
		UNLOCK_LAST_MULTI(step);				\
		IFMULTI_LOCK_RECURSIVE((step).i_if);			\
		(inm) = (step).i_if->if_multiaddrs;			\
		(step).i_lastif = (step).i_if;				\
		(step).i_if = (step).i_if->if_next;			\
		if ((inm) != NULL) {					\
			(step).i_inm = (inm)->inm_next;			\
			break;						\
		}							\
	}								\
}


#define IN_FIRST_MULTI(step, inm)					\
	/* struct in_multistep  step; */				\
	/* struct in_multi     *inm;  */				\
{									\
	(step).i_if  = ifnet;		                                \
	(step).i_inm = NULL;						\
	(step).i_lastif = NULL;						\
	IN_NEXT_MULTI((step), (inm));					\
}

struct in_multi *in_addmulti(struct in_addr , struct ifnet *, cid_t kcid, int *ret, struct inpcb *parent_inpcb);
struct in_multi *in_addmulti_nolock(struct in_addr , struct ifnet *, cid_t kcid, int *ret, struct inpcb *parent_inpcb);
int	in_delmulti_source(struct in_multi *, struct source_info *, struct inpcb *parent_inpcb);
int	in_delmulti(struct in_multi *, struct inpcb *);
struct source_info *in_changemulti_nolock(struct in_multi *, 
struct source_info *, char, struct in_addr, struct ifnet *);
struct source_info *in_changemulti(struct in_multi *, 
struct source_info *, char, struct in_addr);
struct in_multi *in_addmulti_source(struct ifnet *, 
                                    struct in_multi *,
                                    struct source_info **, 
									char, 
									struct in_addr, 
									struct in_addr, 
									cid_t kcid,
									struct inpcb *);
struct in_multi *in_addmulti_sources(struct ifnet *, 
                                     struct in_multi *,
                                     struct source_info **, 
                                     char, 
                                     struct in_addr, 
                                     int, 
                                     struct in_addr *, 
                                     cid_t kcid,
                                     struct inpcb *);
struct source_info *in_changemulti_sources_nolock( struct in_multi *,
struct source_info *, char, int, struct in_addr *, struct ifnet *);
void	inm_init(struct in_multi *, struct in_addr , struct ifnet *);
void	inm_scrub(struct in_multi *);
void	in_change_filter(struct in_multi *);
void	in_del_addrlist(struct in_multi *, struct source_info *);
void	in_change_addrlist(struct in_multi *, struct in_addr , int, int);
void	mergefl(struct in_multi *, struct filter_list *,
struct address_list *, struct address_list *);
void	mergereport(struct in_multi *, struct address_list *, 
struct address_list *);
#endif /* _KERNEL */
#endif /* IP_MULTICAST */

#define INADDR_HASHSZ   229
#define INADDR_HASH2(addr) ((addr) % INADDR_HASHSZ)

struct in_addr_hash {
	struct in_addr_hash *iah_nxt;
	struct in_addr iah_ia;
	struct ifnet *iah_ifp;
	int	iah_flags;
	unsigned short	iah_cid;
	struct wpar_per_ifnet *wp_ifnet;
};

extern struct in_addr_hash *in_addr_hash_table[INADDR_HASHSZ];
extern simple_lock_data_t in_addr_hash_lock[NET_CACHELINESIZE / sizeof(simple_lock_data_t)];

/* flags for in_addr_hash */
#define IAH_VALID       0x1
#define IAH_BROADCAST   0x2

#define INADDR_HASH_LOCK_DECL() int _iahl;
#define INADDR_HASH_LOCK_INIT() { \
        lock_alloc(in_addr_hash_lock, \
        LOCK_ALLOC_PIN, INADDR_HASH_LOCK_FAMILY, -1); \
        simple_lock_init(in_addr_hash_lock); \
}

#define INADDR_HASH_READ_LOCK()
#define INADDR_HASH_WRITE_LOCK() _iahl = disable_lock(PL_IMP, \
        in_addr_hash_lock)
#define INADDR_HASH_READ_UNLOCK()
#define INADDR_HASH_WRITE_UNLOCK() unlock_enable(_iahl, \
        in_addr_hash_lock)

#ifdef __cplusplus
}
#endif

#endif /* _IN_VAR_H_ */
