/*
 * Public Release 3
 * 
 * $Id: inet_multi.h,v 1.2 1997/07/17 22:41:56 chopps Exp $
 *
 *  Author: Tom Pusateri <pusateri@netedge.com>
 */

/*
 * ------------------------------------------------------------------------
 * 
 * Copyright (c) 1996, 1997 The Regents of the University of Michigan
 * All Rights Reserved
 *  
 * Royalty-free licenses to redistribute GateD Release
 * 3 in whole or in part may be obtained by writing to:
 * 
 * 	Merit GateDaemon Project
 * 	4251 Plymouth Road, Suite C
 * 	Ann Arbor, MI 48105
 *  
 * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE REGENTS OF THE
 * UNIVERSITY OF MICHIGAN AND MERIT DO NOT WARRANT THAT THE
 * FUNCTIONS CONTAINED IN THE SOFTWARE WILL MEET LICENSEE'S REQUIREMENTS OR
 * THAT OPERATION WILL BE UNINTERRUPTED OR ERROR FREE. The Regents of the
 * University of Michigan and Merit shall not be liable for
 * any special, indirect, incidental or consequential damages with respect
 * to any claim by Licensee or any third party arising from use of the
 * software. GateDaemon was originated and developed through release 3.0
 * by Cornell University and its collaborators.
 * 
 * Please forward bug fixes, enhancements and questions to the
 * gated mailing list: gated-people@gated.merit.edu.
 * 
 * ------------------------------------------------------------------------
 * 
 * Copyright (c) 1990,1991,1992,1993,1994,1995 by Cornell University.
 *     All rights reserved.
 * 
 * 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.
 * 
 * GateD is based on Kirton's EGP, UC Berkeley's routing
 * daemon	 (routed), and DCN's HELLO routing Protocol.
 * Development of GateD has been supported in part by the
 * National Science Foundation.
 * 
 * ------------------------------------------------------------------------
 * 
 * Portions of this software may fall under the following
 * copyrights:
 * 
 * Copyright (c) 1988 Regents of the University of California.
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms are
 * permitted provided that the above copyright notice and
 * this paragraph are duplicated in all such forms and that
 * any documentation, advertising materials, and other
 * materials related to such distribution and use
 * acknowledge that the software was developed by the
 * University of California, Berkeley.  The name of the
 * University may not 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.
 */


#define	IPMULTI_PROTO_MOSPF	0	/* Multicast Extensions to OSPF */
#define	IPMULTI_PROTO_DVMRP	1	/* Distance Vector Multicast Routing */
#define	IPMULTI_PROTO_PIM	2	/* Protocol Independent Multicasting */
#define	IPMULTI_PROTO_CBT	3	/* Core Based Trees */
#define	IPMULTI_PROTO_MAX	4

#define IPMULTI_BIT(proto)      ((flag_t) (1 << (proto)))

/*
 * Prune List for sending and timing out prunes
 */

typedef struct _prune_list {
    struct	_prune_list *tq_forw, *tq_back;
    struct	_prune_list *if_forw, *if_back;
    if_addr	*ifap;
    sockaddr_un	*nbr_addr;
    struct	_mfc *mfcp;
    int		pending;
    int		holdtime;
    time_t	prune_time;
} prune_list;


#define PRUNE_TQ_ENQ(elem, pred) { \
    register prune_list *Xe = elem; \
    register prune_list *Xp = pred; \
    Xp->tq_forw = (Xe->tq_forw = (Xe->tq_back = Xp)->tq_forw)->tq_back = Xe; \
}

#define PRUNE_TQ_DEQ(elem) { \
    register prune_list *Xe = elem; \
    (Xe->tq_back->tq_forw = Xe->tq_forw)->tq_back = Xe->tq_back; \
}

#define PRUNE_IF_ENQ(elem, pred) { \
    register prune_list *Xe = elem; \
    register prune_list *Xp = pred; \
    Xp->if_forw = (Xe->if_forw = (Xe->if_back = Xp)->if_forw)->if_back = Xe; \
}

#define PRUNE_IF_DEQ(elem) { \
    register prune_list *Xe = elem; \
    (Xe->if_back->if_forw = Xe->if_forw)->if_back = Xe->if_back; \
}

#define	PRUNE_LIST(gp, list)	{ for (gp = (list)->tq_forw; gp != list; gp = gp->tq_forw)
#define PRUNE_LIST_END(gp, list)	if (gp == list) gp = (prune_list *) 0; }

/*
 * The MFC Source list structure is a linked list of MFC's that hang off
 * the unicast route back to the source. This is convenient when the
 * unicast routing table changes. PIM is notified via the flash routine
 * and decide if a new upstream interface is needed.
 */

typedef struct _mfc_src_list {
    struct _mfc_src_list *forw;
    struct _mfc_src_list *back;
    struct _mfc *mfcp;
} mfc_src_list;

/*
 * The ifnbr list keeps a list of all neighbors that want an MFC.
 * If no more nbrs want an MFC, it can be pruned on that interface.
 * When all downstream interfaces have pruned it, it can be pruned upstream.
 */

typedef struct _ifnbr {
    struct _ifnbr *forw;
    struct _ifnbr *back;
    sockaddr_un	  *nbr_addr;
} ifnbr;

extern block_t mfc_unicast_block_index;


/* A multicast forwarding cache entry */

typedef struct _mfc {
    struct _mfc *left;			/* tree branches */
    struct _mfc *right;			/* tree branches */
    u_long	mfc_src;		/* source */
    u_long	mfc_mask;		/* for use in building the tree */
    int		mfc_lastuse;		/* previous use count from the kernel */
    int		mfc_use;		/* most recent use count */
    time_t	mfc_ctime;		/* creation time */
    time_t	mfc_rtime;		/* last refresh time */
    if_addr	*upstream_ifap;		/* the upstream interface */
    int		ds_count;		/* the number of downstream intfs */
    struct _downstream *ds;		/* the list of downstream interfaces */
    struct _group_node *mfc_group;	/* backpointer to head of tree */
    u_long	mfc_proto;		/* current protocols using this mfc */
    void	(*mfc_callback)();	/* routine to call when RTM_GET rx'ed */

					/* Protocol section */
    struct _prune_list *prune_up;	/* pruned upstream */
    struct _prune_list prune_down;	/* head of interface prune list */

					/* PIM section */
    u_long	rpf_addr;		/* addr to use when sending upstream */
    struct _mfc_src_list *msl;		/* ptr back to unicast route to src */
    struct _assert_list *pim_assert;	/* store 1st assert received */

					/* DVMRP section */
    void_t	mfc_graft;		/* awaiting graft ack for this (G,S) */
} mfc;

typedef struct _group_node {
    struct	_group_node *left;	/* tree branches */
    struct	_group_node *right;	/* tree branches */
    u_long	group_key;		/* group address */
    u_long	group_mask;		/* for use in building the tree */
    u_short	src_node_count;		/* number sources in this source tree */
    u_short	graft_pending;		/* awaiting graft ack for this group */
    struct	_mfc *src_head;		/* this points to head of source tree */
} group_node;

typedef struct _downstream {
    struct	_downstream *forw;	/* linked list off mfc */
    struct	_downstream *back;	/* linked list off mfc */
    struct	_downstream *tq_forw;	/* linked list for timer queue */
    struct	_downstream *tq_back;	/* linked list for timer queue */
    sockaddr_un	*ds_addr;		/* address of downstream intf or nbr */
    u_short	ds_ttl;			/* minimum ttl - 0 disabled */
    u_short	ds_flags;		/* flags: nbr, age, grafts, etc. */
    u_long	ds_proto;		/* protocols in RTPROTO_BIT */
    int		ds_ifindex;		/* ifindex for tunnels */
    time_t	ds_timeout;		/* timeout value for this interface */
    struct	_ifnbr ds_nbrlist;	/* DVMRP downstream neighbors */
} downstream;

/*
 * Assert List for receiving and timeout out asserts
 */

typedef struct _assert_list {
    struct	_assert_list *forw, *back;
    mfc		*mfcp;
    if_addr	*ifap;
    u_long	rpf_addr;
    time_t	assert_time;
    u_long	preference;
    u_long	metric;
    int		rpbit;
} assert_list;


/*
 * Used to scan mfc entries when aging
 */

#define	MFC_TIMEOUT_LIST(gp, list)	{ for (gp = (list)->forw; gp != list; gp = gp->forw)
#define MFC_TIMEOUT_LIST_END(gp, list)	if (gp == list) gp = (mfc *) 0; }

/*
 * Used to scan the downstream interface list
 */

#define	DOWNSTREAM_LIST(gp, list)	{ for (gp = (list)->forw; gp != list; gp = gp->forw)
#define DOWNSTREAM_LIST_END(gp, list)	if (gp == list) gp = (downstream *) 0; }

/*
 * returned structure when locating upstream interfaces and neighbors
 */

typedef struct _upstream {
    if_addr	*ifap;
    sockaddr_un	*nbr;
    int		protocol;
    metric_t	metric;
} upstream;


PROTOTYPE(mfc_init,
	  extern void,
	  (void));

PROTOTYPE(mfc_alloc_node,
	  extern mfc *,
	  (void));

PROTOTYPE(mfc_alloc_downstream,
	  extern downstream *,
	  (void));

PROTOTYPE(mfc_free_downstream,
	  extern void,
	  (downstream *));

PROTOTYPE(mfc_add_node,
	  extern int,
	  (sockaddr_un *, mfc *));

PROTOTYPE(mfc_delete_node,
	  extern void,
	  (mfc *));

PROTOTYPE(mfc_dump,
	  extern void,
	  (task *,
	   FILE *));

PROTOTYPE(mfc_terminate,
	  extern void,
	  (void));

PROTOTYPE(mfc_visit,
	  extern void,
	  (_PROTOTYPE(func,
		      void,
		      (mfc *,
		       caddr_t)),
	  caddr_t));

PROTOTYPE(mfc_source_visit,
	  extern void,
	  (group_node *,
	  _PROTOTYPE(func,
		     void,
		     (mfc *,
		      caddr_t)),
	  caddr_t));

PROTOTYPE(mfc_locate_group,
	  extern group_node *,
	  (u_long));

PROTOTYPE(mfc_locate_mfc,
	  extern mfc *,
	  (sockaddr_un *,
	   sockaddr_un *));

PROTOTYPE(mfc_source_link_unicast,
	  extern void,
	  (task *,
	   mfc *));

PROTOTYPE(mfc_source_unlink_unicast,
	  extern void,
	  (task *,
	   mfc *));
