/* * Gated Release 4.x, 5.x, 6.x, 7.x * * Copyright (c) 1996,1997,1998 The Regents of the University of Michigan. * All Rights Reserved. * * License to use, copy, modify, and distribute this software and its * documentation can be obtained from Merit at the University of Michigan. * * 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. * * This copyright has ben automatically added by util/addcopyright.pl. * __END_OF_COPYRIGHT__ */ /* * Copyright (c) 1997 by the University of Southern California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and * its documentation in source and binary forms for lawful * non-commercial purposes and without fee is hereby granted, provided * that the above copyright notice appear in all copies and that both * the copyright notice and this permission notice appear in supporting * documentation, 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 Southern * California and/or Information Sciences Institute. * The name of the University of Southern California may not * be used to endorse or promote products derived from this software * without specific prior written permission. * * THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS * ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. 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, TITLE, AND * NON-INFRINGEMENT. * * IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT, * TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH, * THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Questions concerning this software should be directed to * eddy@isi.edu. * * $Id: mrt.h,v 1.28 1998/11/21 03:47:52 eddy Exp $ */ /* * The Merit (Gated) copyright covers the basic algorithms derived from * rt_radix.c, the USC copyright applys the multicast route table * adaptation of the rt_radix.c code. */ #ifndef __MRT_H__ #define __MRT_H__ #define MRT 1.0 /* Note that 0 is reserved because in igmp_if_proto, these are values * instead of bits, and we need a default value for none. */ #define IPMULTI_PROTO_NONE 0 /* default */ #define IPMULTI_PROTO_MOSPF 1 /* Multicast Extensions to OSPF */ #define IPMULTI_PROTO_DVMRP 2 /* Distance Vector Multicast Routing */ #define IPMULTI_PROTO_PIM 3 /* Protocol Independent Multicasting */ #define IPMULTI_PROTO_CBT 4 /* Core Based Trees */ #define IPMULTI_PROTO_PIMSM 5 /* Handle PIM-SM and PIM-DM seperately */ #define IPMULTI_PROTO_PIMDM 6 /* ditto */ #define IPMULTI_PROTO_BGMP 7 /* Border Gateway Multicast Protocol */ #define IPMULTI_PROTO_MAX 8 #define IPMULTI_BIT(proto) ((flag_t) (1 << (proto))) #define NODE_NOMASK 0xffffffff /* * The Address families, as per IANA */ #define ADDRF_RESERVED 0 #define ADDRF_IPv4 1 #define ADDRF_IPv6 2 #define ADDRF_NSAP 3 #define ADDRF_HDLC 4 #define ADDRF_BBN1822 5 #define ADDRF_802 6 #define ADDRF_E163 7 #define ADDRF_E164 8 #define ADDRF_F69 9 #define ADDRF_X121 10 #define ADDRF_IPX 11 #define ADDRF_APPLETALK 12 #define ADDRF_DECNETIV 13 #define ADDRF_BANYAN 14 #define ADDRF_E164NSAP 15 #define ADDRT_IPv4_NONE 0 #define ADDRT_IPv4 ADDRT_IPv4_NONE /* * XXX Assumes NBBY is 8. If it isn't we're in trouble anyway. */ #define RN_ADDR(addr, a_offset) (((byte *)(addr)) + a_offset) #define RN_BYTELEN(x) ((unsigned) ((x) + RNBBY - 1) >> RNSHIFT) #define RNBBY 8 #define RNSHIFT 3 #define RNBIT(x) (0x80 >> ((x) & (RNBBY-1))) #define RNBYTE(x) ((x) >> RNSHIFT) #define MAXKEYBITS (SOCK_MAXADDRLEN * RNBBY) #define MAXDEPTH (MAXKEYBITS+1) #define IS_CLASSD(dst) \ (IN_MULTICAST(ntohl(sock2ip (dst)))) ? dst : (sockaddr_un *) 0 typedef struct group_ group_t; typedef struct source_ source_t; typedef struct upstream_ upstream_t; typedef struct mrt_node_ mrt_node_t; typedef struct mrt_table_ mrt_table_t; /* * for the purpose of a border router, upstream really * represents the component, wereas the kernel only cares * about interfaces. so the component is free to alter the * ifap (and nbr) fields for it's own purpose and the * mbr layer can determine the component by * mbr_get_iftask(up->ifap). */ struct upstream_ { if_addr *ifap; /* incase iif != RT_IFAP(rt) */ sockaddr_un *nbr; /* incase nbr != RT_ROUTER(rt) */ rt_entry *rt; /* unicast route from RIB_MULTICAST */ int protocol; /* used for mtrace */ sockaddr_un *srcmask; /* inet mask of the iif */ pref_t pref; /* pref and metric of this upstream */ metric_t metric; /* */ }; #define up_vif ifap->ifa_vif #define src_ifap src_upstream->ifap #define src_nbr src_upstream->nbr #define src_rt src_upstream->rt #define src_metric src_upstream->metric #define src_preference src_upstream->pref #define src_up_proto src_upstream->protocol /* Just because it's used alot */ #define ifa_name ifa_link->ifl_name typedef struct downstream_ { struct downstream_ *forw, *back; if_addr *ds_ifap; /* ifap to send mcast pkts out */ u_int8 ds_protos; /* local and/or remote (igmp/mcast proto) */ int ds_count; /* the number of claims on this downstream entry */ time_t ds_ctime; /* creation time */ time_t ds_rtime; /* last refresh time */ time_t ds_timeout; /* time in seconds this value is good */ time_t ds_holdtime; /* holdtime of the ds ifap */ void_t ds_data; /* protocol specific data */ } downstream_t; #define ds_vif ds_ifap->ifa_vif #define DSPROTO_NONE 0x0 /* noboady cares about this */ #define DSPROTO_IGMP 0x1 /* IGMP */ #define DSPROTO_MROUTE 0x2 /* ifaps component mcast proto */ #define DSPROTO_WC 0x4 /* This was placed as a result of wc expansion */ #define DSPROTO_RP 0x8 /* for ifap added via (*,*,rp) */ #define DSPROTO_STATIC 0x10 /* static join */ #define DSPROTO_MBR 0x20 /* requested by another component */ #define DSPROTO_BGMP 0x40 /* requested by bgmp */ #define DSPROTO_ALL (DSPROTO_IGMP|DSPROTO_MROUTE|DSPROTO_WC|DSPROTO_RP|DSPROTO_STATIC|DSPROTO_MBR) /* * XXX: maybe the downstream list should be an array of downstream_t pointers * indexed by vif. it will save quite a bit doing searches and copies and * is much more convinient. */ #ifndef MAXVIFS #define MAXVIFS 32 /* XXX: should get this from ip_mroute.h */ #endif struct source_ { sockaddr_un *addr; /* ip addr */ sockaddr_un *mask; /* ip addr mask */ struct mrt_node_ *node; /* pointer back to the radix node */ group_t *src_group; /* pointer to the group */ upstream_t *src_upstream; /* upstream iif */ int src_ndownstream; /* # of downstream if's, XXX: remove this. */ downstream_t *src_downstream; /* oif list */ downstream_t *src_dstable[MAXVIFS]; /* downstream entries index by vifnum */ struct component_ *src_components; /* mbr keeps track of interested components */ int src_ncomponents; /* XXX: src_flags changed from 8 bit to 32 bits */ u_int32 src_flags; /* flags, used by the owning proto */ void_t src_data[3]; /* component specific use */ int src_proto; /* owner protocol */ u_long src_pktcnt; /* latest pkt cnt */ u_long src_bytecnt; /* latest byte cnt */ u_long src_wrongiif; /* */ time_t src_stattime; /* the last stat time */ u_long src_lastpktcnt; /* previous pkt cnt */ u_long src_lastbytecnt; /* previous byte cnt */ u_long src_lastwrongiif; /* */ time_t src_laststattime; /* the previous stat time */ time_t src_ctime; /* creation time */ time_t src_rtime; /* refresh time */ time_t src_timeout; /* system time which this entry is expired */ time_t src_holdtime; /* the holdtime in seconds for this entry */ }; /* XXX: for dvmrp.c */ #define src_use src_bytecnt #define src_lastuse src_lastbytecnt #define src_gaddr src_group->addr #define src_gmask src_group->mask #define src_rt src_upstream->rt #define src_ifap src_upstream->ifap #define src_nbr src_upstream->nbr #define src_vif src_ifap->ifa_vif #define src_task src_group->grp_table->mrt_task #define MRT_RPT 0x00000001 /* is this on a shared tree */ #define MRT_WC 0x00000002 /* is this a wildcard entry */ #define MRT_SPT 0x00000004 /* is this on the shortest path */ #define MRT_NEG_CACHE 0x00000008 /* is this a negative cache */ #define MRT_JOIN_SUPP 0x00000010 /* suppress joins */ #define MRT_CACHED 0x00000020 /* this is for kernel cached entries */ #define MRT_EXPANDED 0x00000040 /* this is an s,g entry expanded for a wc entry */ #define MRT_WRONGIF 0x00000080 /* for assert messages */ #define MRT_UNUSED1 0x00000100 /* this caused by data */ #define MRT_EXTERNAL 0x00000200 /* this was requested from an external component */ #define MRT_SRC_TASK(src) (src)->src_group->grp_table->mrt_task #define MRT_IS_WC(src) (BIT_TEST(src->src_flags, MRT_WC)) #define MRT_WILDCARD 0xe0000000 /* 224.0.0.0 */ #define MRT_WILDCARD_MASKLEN 4 /* bits */ extern sockaddr_un *mrt_wildcard; /* 224.0.0.0 */ extern sockaddr_un *mrt_wildcard_mask; /* /4 */ extern int mrt_wildcard_masklen; #define MRT_SRC_TASK(src) (src)->src_group->grp_table->mrt_task struct group_ { sockaddr_un *addr; sockaddr_un *mask; mrt_node_t *node; /* pointer back to the radix node */ mrt_table_t *grp_table; /* pointer back to the table that owns us */ mrt_table_t *grp_srcs; /* radix trie of sources for this group */ }; typedef struct mrt_addr_ { sockaddr_un *addr; sockaddr_un *mask; struct mrt_node_ *node; /* pointer back to the radix node */ } mrt_addr_t; struct mrt_node_ { struct mrt_node_ *rn_left; /* bit clear */ struct mrt_node_ *rn_right; /* bit set */ struct mrt_node_ *rn_parent; /* parent */ u_short rn_bit; /* bit for node mask */ u_char rn_tbyte; /* byte to test */ u_short rn_tbit; /* test bit within tbyte */ void_t rn_ext; /* pointer to the extern */ }; #define rn_addr rn_ext->addr #define rn_node rn_ext->node typedef struct addr_list_ { struct addr_list_ *forw; sockaddr_un *addr; sockaddr_un *mask; } addr_list; typedef struct mrt_src_list_ { struct mrt_src_list_ *forw, *back; source_t *src; } mrt_src_list_t; typedef struct mrt_grp_list_ { struct mrt_grp_list_ *forw, *back; group_t *grp; } mrt_grp_list_t; typedef struct mrt_list_ { struct mrt_list_ *forw, *back; } mrt_list_t; /* Used to scan a mrt_list (list of source_t) entries */ #define MRT_SRC_LIST(gp, list) { for (gp = (list)->forw; gp != list; gp = gp->forw) #define MRT_SRC_LIST_END(gp, list) if (gp == list) gp = (mrt_src_list_t *) 0; } #define MRT_TIMEOUT_LIST(gp, list) { for (gp = (list)->forw; gp != list; gp = gp->forw) #define MRT_TIMEOUT_LIST_END(gp, list) if (gp == list) gp = (mrt_src_list_t *) 0; } #define MRT_SRC_LIST_ENQ(elem, pred) { \ register mrt_src_list_t *Xe = (mrt_src_list_t *) (elem); \ register mrt_src_list_t *Xp = (mrt_src_list_t *) (pred); \ Xp->forw = (Xe->forw = (Xe->back = Xp)->forw)->back = Xe; \ } #define MRT_SRC_LIST_DEQ(elem) { \ register mrt_src_list_t *Xe = elem; \ (Xe->back->forw = Xe->forw)->back = Xe->back; \ } #define MRT_SRC_LIST_ADD(src, list) { \ register mrt_src_list_t *s = \ (mrt_src_list_t *) mrt_src_list_alloc(); \ MRT_SRC_LIST_ENQ(s, ((mrt_src_list_t *) list)->back); \ s->src = (source_t *) (src); \ } #define MRT_SRC_LIST_DELETE(elem) { \ MRT_SRC_LIST_DEQ(elem); \ mrt_src_list_free(elem); \ } #define MRT_GRP_LIST(gp, list) { for (gp = (list)->forw; gp != list; gp = gp->forw) #define MRT_GRP_LIST_END(gp, list) if (gp == list) gp = (mrt_grp_list_t *) 0; } #define MRT_GRP_LIST_ENQ(elem, pred) { \ register mrt_grp_list_t *Xe = (mrt_grp_list_t *) (elem); \ register mrt_grp_list_t *Xp = (mrt_grp_list_t *) (pred); \ Xp->forw = (Xe->forw = (Xe->back = Xp)->forw)->back = Xe; \ } #define MRT_GRP_LIST_DEQ(elem) { \ register mrt_grp_list_t *Xe = elem; \ (Xe->back->forw = Xe->forw)->back = Xe->back; \ } #define MRT_GRP_LIST_ADD(grp, list) { \ register mrt_grp_list_t *s = \ (mrt_grp_list_t *) mrt_grp_list_alloc(); \ MRT_GRP_LIST_ENQ(s, ((mrt_grp_list_t *) list)->back); \ s->grp = (group_t *) (grp); \ } #define MRT_GRP_LIST_DELETE(elem) { \ MRT_GRP_LIST_DEQ(elem); \ mrt_grp_list_free(elem); \ } /* * Multicast route table structure. */ struct mrt_table_ { struct mrt_table_ *forw, *back; /* remove these */ mrt_node_t *mrt_head; /* head of the mrt_table */ u_long mrt_inodes; /* # of internal nodes */ u_long mrt_routes; /* # of routes in the table */ struct sock_info *mrt_sinfo; /* socket info for this proto */ char *mrt_name; /* human readable */ task *mrt_task; /* task that owns us */ }; typedef struct mrt_test_ mrt_test_t; struct mrt_test_ { mrt_test_t *forw; int mt_cmd; u_long mt_gaddr; int mt_glen; u_long mt_saddr; int mt_slen; }; #define MRTA_NONE 0 #define MRTA_ADD 1 /* Add an entry to the mrt */ #define MRTA_DEL 2 /* Del an entry from the mrt */ #define MRTA_EXACT 3 /* Try an exact match */ #define MRTA_BEST 4 /* Try a best match */ #define MRTA_DUMP 5 /* do a radix trie dump */ #define MRTA_WALKDOWN 6 /* do a walk down of the radix trie */ #define MRTA_WALKUP 7 /* walkup the trie, NOT Supported */ #define MRTA_DELTABLE 8 /* delete the table */ #define MRTA_BAD 9 /* Too far */ /* * 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_t *) 0; } #define DOWNSTREAM_TQ(gp, list) { for (gp = (list)->tq_forw; gp != list; gp = gp->tq_forw) #define DOWNSTREAM_TQ_END(gp, list) if (gp == list) gp = (downstream_t *) 0; } #define DOWNSTREAM_ENQ(elem, pred) { \ register downstream_t *Xe = (downstream_t *) (elem); \ register downstream_t *Xp = (downstream_t *) (pred); \ Xp->forw = (Xe->forw = (Xe->back = Xp)->forw)->back = Xe; \ } /* * must not be called on the only element in the list */ #define DOWNSTREAM_DEQ(elem) { \ register downstream_t *Xe = (downstream_t *) (elem); \ Xe->back->forw = Xe->forw; \ Xe->forw->back = Xe->back; \ } #define DOWNSTREAM_IS_NULL(S) (S->src_downstream == S->src_downstream->forw) #define ADD_TIMEQ(elem, pred) pred->tq_forw = \ (elem->tq_forw = (elem->tq_back = pred)->tq_forw)->tq_back = elem #define DEL_TIMEQ(elem) (elem->tq_back->tq_forw = elem->tq_forw)->tq_back = elem->tq_back /* * Used when walking through the radix tree, to remember where we are :) */ typedef struct mrtwalk_ { struct mrtwalk_ *forw, *back; mrt_node_t *mw_gnode; /* current node */ mrt_node_t *mw_snode; mrt_node_t *mw_gstart; /* starting point */ mrt_node_t *mw_sstart; int rw_way; /* Way to walk the tree (RTW_xx) */ int mw_len; /* Length of mask where we started */ } mrtwalk_t; #define MRT_ENQ(elem, pred) { \ register mrt_table_t *Xe = elem; \ register mrt_table_t *Xp = pred; \ Xp->forw = (Xe->forw = (Xe->back = Xp)->forw)->back = Xe; \ } #define MRT_DEQ(elem) { \ register mrt_table_t *Xe = elem; \ (Xe->back->forw = Xe->forw)->back = Xe->back; \ } #define MRT_TABLES(mrt) do { \ mrt_table_t *Xmrt = mrt_tables.forw; \ while (Xmrt != &mrt_tables) { \ (mrt) = Xmrt; \ Xmrt = Xmrt->forw; \ do #define MRT_TABLES_END(mrt) while(0); } } while(0) #define MRT_WALK(head, ext) \ do { \ mrt_node_t *Xstack[MAXDEPTH]; \ mrt_node_t **Xsp = Xstack; \ mrt_node_t *Xrn = (head)->mrt_head; \ while (Xrn) { \ if (((ext) = Xrn->rn_ext)) do #define MRT_WALK_END(head, ext) \ while(0); \ if (Xrn->rn_left) { \ if (Xrn->rn_right) { \ *Xsp++ = Xrn->rn_right; \ } \ Xrn = Xrn->rn_left; \ } else if (Xrn->rn_right) { \ Xrn = Xrn->rn_right; \ } else if (Xsp != Xstack) { \ Xrn = *(--Xsp); \ } else { \ Xrn = (mrt_node_t *) 0; \ (ext) = (void_t) 0; \ } } } while (0) #define MRT_WALK2(head2, ext2) \ do { \ mrt_node_t *X2stack[MAXDEPTH]; \ mrt_node_t **X2sp = X2stack; \ mrt_node_t *X2rn = (head2)->mrt_head; \ while (X2rn) { \ if (((ext2) = X2rn->rn_ext)) do #define MRT_WALK_END2(head2, ext2) \ while(0); \ if (X2rn->rn_left) { \ if (X2rn->rn_right) { \ *X2sp++ = X2rn->rn_right; \ } \ X2rn = X2rn->rn_left; \ } else if (X2rn->rn_right) { \ X2rn = X2rn->rn_right; \ } else if (X2sp != X2stack) { \ X2rn = *(--X2sp); \ } else { \ X2rn = (mrt_node_t *) 0; \ (ext2) = (void_t) 0; \ } } } while (0) #define MRT_WALK_SRC(head, src) \ do { \ group_t *Xgrp; \ MRT_WALK(head, Xgrp) { \ mrt_node_t *XXstack[MAXDEPTH]; \ mrt_node_t **XXsp = XXstack; \ mrt_node_t *XXrn = Xgrp->grp_srcs->mrt_head; \ while (XXrn) { \ if (((src) = (source_t *) XXrn->rn_ext)) do #define MRT_WALK_SRC_END(head, src) \ while(0); \ if (XXrn->rn_left) { \ if (XXrn->rn_right) { \ *XXsp++ = XXrn->rn_right; \ } \ XXrn = XXrn->rn_left; \ } else if (XXrn->rn_right) { \ XXrn = XXrn->rn_right; \ } else if (XXsp != XXstack) { \ XXrn = *(--XXsp); \ } else { \ XXrn = (mrt_node_t *) 0; \ (src) = (source_t *) 0; \ } } } MRT_WALK_END(head, Xgrp); \ } while(0) #define MRT_GRP_WALK(gnode, grp) \ do { \ mrt_node_t *XGstack[MAXDEPTH]; \ mrt_node_t **XGsp = XGstack; \ mrt_node_t *XGrn = (gnode); \ while (XGrn) { \ if (((grp) = (group_t *) XGrn->rn_ext)) do #define MRT_GRP_WALK_END(gnode, grp) \ while (0); \ if (XGrn->rn_left) { \ if (XGrn->rn_right) { \ *XGsp++ = XGrn->rn_right; \ } \ XGrn = XGrn->rn_left; \ } else if (XGrn->rn_right) { \ XGrn = XGrn->rn_right; \ } else if (XGsp != XGstack) { \ XGrn = *(--XGsp); \ } else { \ XGrn = (mrt_node_t *) 0; \ (grp) = (group_t *) 0; \ } } } while (0) #define MRT_SRC_WALK(snode, src) \ do { \ mrt_node_t *XSstack[MAXDEPTH]; \ mrt_node_t **XSsp = XSstack; \ mrt_node_t *XSrn = (snode); \ while (XSrn) { \ if (((src) = XSrn->rn_ext)) do #define MRT_SRC_WALK_END(p, src) \ while (0); \ if (XSrn->rn_left) { \ if (XSrn->rn_right) { \ *XSsp++ = XSrn->rn_right; \ } \ XSrn = XSrn->rn_left; \ } else if (XSrn->rn_right) { \ XSrn = XSrn->rn_right; \ } else if (XSsp != XSstack) { \ XSrn = *(--XSsp); \ } else { \ XSrn = (mrt_node_t *) 0; \ (src) = (void_t) 0; \ } } } while (0) #define RN_SETBIT(rn, bitlen, lastmask) \ do { \ register mrt_node_t *Xrn = (rn); \ register u_short Xlen = (u_short)(bitlen); \ Xrn->rn_bit = Xlen; \ if ((lastmask)) { \ Xrn->rn_tbyte = 0; \ Xrn->rn_tbit = 0; \ } else { \ Xrn->rn_tbyte = RNBYTE(Xlen); \ Xrn->rn_tbit = RNBIT(Xlen); \ } \ } while (0) #define mrt_locate_group(Xmrt, Xgaddr) (group_t *) mrt_locate(Xmrt, Xgaddr) #define mrt_locate_group_mask(mrt, gaddr, gmask) \ (group_t *) mrt_locate_mask (mrt, gaddr, gmask) #define mrt_locate_addr(Xmrt, Xaddr) (mrt_addr_t *) mrt_locate(Xmrt, Xaddr) PROTOTYPE(mrt_init, void, (void)); PROTOTYPE(mrt_terminate, void, (void)); PROTOTYPE(mrt_terminate_table, void, (mrt_table_t *mrt)); PROTOTYPE(mrt_print_table, void, (FILE *, mrt_table_t *)); PROTOTYPE(mrt_print_grp, void, (FILE *, group_t *)); PROTOTYPE(mrt_print_src, void, (FILE *, source_t *)); PROTOTYPE(mrt_print_subtree, void, (mrt_table_t *, sockaddr_un *, sockaddr_un *, sockaddr_un *, sockaddr_un *)); PROTOTYPE(mrt_dump, void, (task *, FILE *)); PROTOTYPE(mrt_dump_table, void, (mrt_table_t *, FILE *)); PROTOTYPE(mrt_addr_alloc, mrt_addr_t *, (void)); PROTOTYPE(mrt_table_add, void, (mrt_table_t *, mrt_addr_t *)); PROTOTYPE(mrt_table_create, mrt_table_t *, (task *, int, const char *)); PROTOTYPE(mrt_table_remove, void, (mrt_table_t *, mrt_addr_t *)); PROTOTYPE(mrt_downstream_alloc, downstream_t *, (void)); PROTOTYPE(mrt_downstream_create, downstream_t *, (void)); PROTOTYPE(mrt_downstream_cmp, int, (downstream_t *, downstream_t *)); PROTOTYPE(mrt_downstream_dup, downstream_t *, (downstream_t *)); PROTOTYPE(mrt_downstream_copy, int, (downstream_t **, downstream_t *, if_addr *)); PROTOTYPE(mrt_upstream_dup, upstream_t *, (upstream_t *)); PROTOTYPE(mrt_locate, void *, (mrt_table_t *mrt, sockaddr_un *)); PROTOTYPE(mrt_locate_mask, void *, (mrt_table_t *mrt, sockaddr_un *, sockaddr_un *)); PROTOTYPE(mrt_locate_source, source_t *, (mrt_table_t *,sockaddr_un *, sockaddr_un *)); PROTOTYPE(mrt_locate_source_mask, source_t *, (mrt_table_t *, sockaddr_un *, sockaddr_un *, sockaddr_un *, sockaddr_un *)); PROTOTYPE(mrt_match_node, mrt_node_t *, (mrt_table_t *, sockaddr_un *)); PROTOTYPE(mrt_match_node_mask, mrt_node_t *, (mrt_table_t *, sockaddr_un *, sockaddr_un *)); PROTOTYPE(mrt_longest_match_source, source_t *, (mrt_table_t*,sockaddr_un *, sockaddr_un *)); PROTOTYPE(mrt_create_group_mask, group_t *, (mrt_table_t *, sockaddr_un *, sockaddr_un *)); PROTOTYPE(mrt_create_group, group_t *, (mrt_table_t *, sockaddr_un *)); PROTOTYPE(mrt_create_source_mask, source_t *, (group_t *, sockaddr_un *, sockaddr_un *)); PROTOTYPE(mrt_create_source, source_t *, (group_t *, sockaddr_un *)); PROTOTYPE(mrt_create_entry_mask, source_t *, (mrt_table_t *, sockaddr_un *, sockaddr_un *, sockaddr_un *, sockaddr_un *)); PROTOTYPE(mrt_create_entry, source_t *, (mrt_table_t *, sockaddr_un *, sockaddr_un *)); PROTOTYPE(mrt_source_delete, void, (source_t *)); PROTOTYPE(mrt_src_list_alloc, mrt_src_list_t *, (void)); PROTOTYPE(mrt_table_delete, void, (mrt_table_t *)); PROTOTYPE(mrt_downstream_free, void, (downstream_t *ds)); PROTOTYPE(mrt_src_list_alloc, mrt_src_list_t *, (void)); PROTOTYPE(mrt_src_find, mrt_src_list_t *, (source_t *, mrt_src_list_t *)); PROTOTYPE(mrt_addr_list_alloc, addr_list *, (void)); PROTOTYPE(mrt_upstream_delete, void, (upstream_t *)); PROTOTYPE(mrt_upstream_alloc, upstream_t *, (void)); PROTOTYPE(mrt_walk_start, mrt_node_t *, (mrt_table_t *,sockaddr_un *, sockaddr_un *, int)); PROTOTYPE(mrt_test, void, (mrt_table_t *, mrt_test_t *)); PROTOTYPE(mrt_upstream_dup, upstream_t *, (upstream_t *)); PROTOTYPE(psrc, char *, (source_t *)); #endif /*__MRT_H__*/