/* $Id: pim_router.c,v 1.1 1999/08/23 16:18:37 naamato Exp $ */
/*
 * Copyright(c) 1998 by Hitachi.Ltd All rights reserved.
 *
 */

#include "defs.h"
#include "igmp_def.h"
#include "dvmrp_def.h"
#include "pim_def.h"
#include "interface.h"

#define  PIM_DR 2
#define  UP 1
#define  DOWN 0

#define PRUNE 1
#define GRAFT 2

#define PIM_PKT  (struct pim_header *)(send_buf+IPHDR_LEN)

struct NODE_IF {
    struct NODE_IF *next;
    struct if_addr *ifa;
    u_long local_addr;
    u_long remote_addr;
    short  state;
    short  protocol;
    char *if_ps;
};
    
struct NODE {
    struct NODE *next;
    u_long node_id;
    struct NODE_IF ifaddr;
    FILE *trace_fp;
    char *trace_file;
};

struct ROUTE {
    struct ROUTE *next;
    u_long addr;
    u_long mask;
    u_long gateway;
    int metric;
    int state;
};

struct NET_LIST {
    struct NET_LIST *next;
    int id;
    struct ROUTE *routes;
};

struct pim_nbr {
    struct pim_nbr *next;
    u_long addr;
    short opt_type;   /* Option type : holdtime */
    short opt_len;
    u_long opt_val;
    int state;
    u_long recv_time;
};

struct vif_info {
    u_long lcl_addr;
    u_long rmt_addr;
    u_long netmask;
    struct if_info *ifap;
    struct pim_nbr *nbrs;
};

struct network_list {
    struct network_list *next;
    u_long addr;
    u_long mask;
    int metric;
};

struct prune_list {
    struct prune_list *next;
    u_long src;
    u_long grp;
    int lifetime;
    int state;        /* Prune or Graft */
    u_long nbr_addr;
};

struct member {
    struct member *next;
    u_long group;
};

struct pim_data {
    struct NODE *node;
    int hello_time;
    char *htimer;
    int jp_time;
    char *jptimer;
    int bsr_period;
    char *bsrtimer;
    int nbr_time;
    char *ntimer;
    int bsr_pri;
    short opt_type;
    short opt_len;
    u_long opt_val;
    struct member *member_list;
    struct prune_list *prunes;
    struct bsr_list *bsrs;
    struct pim_nbr *nbrs;
    int nbr_count;
    char *adv_bsr;
    int adv_bsr_list;
    char *adv_crp;
    int adv_crp_list;
    char *adv_jp;
    int adv_jp_list;
    int vifs; 
    int state;
};

struct src_entry {
    struct src_entry *next;
    u_long addr;
    u_long upstream;
};

struct sg_entry {
    struct sg_entry *next;
    u_long src;
    u_long group;
    int iif;
    u_long upstream;
};

struct pim_header {
    u_char  type;
    u_char  reserved;
    u_short cksum;
};

struct pim_hello {
    u_short opt_type;
    u_short opt_len;
};

struct pim_eaddr {
    u_char ea_family;
    u_char ea_type;
    u_char ea_flags;
    u_char ea_masklen;
    u_long ea_addr;
};

struct pim_euaddr {
    u_char eu_family;
    u_char eu_type;
    u_long eu_addr;
};

struct rp_list {
    struct rp_list *next;
    u_long addr;
    u_short holdtime;
    u_short priority;
};

struct grp_list {
    struct grp_list *next;
    struct grp_list *grp;
    struct rp_list *rp;
    u_long addr;
    u_long mask;
    int rp_cnt;
};

struct bsr_list {
    struct bsr_list *next;
    struct grp_list *grp;
    struct rp_list *rp;
    u_long bsr_addr;
    u_short frag_tag;
    u_char hashmask;
    u_char priority;
};
    
#define NODE_SEARCH(node,id) \
{ \
    for(node=router_list;node!=NULL;node=node->next) { \
	if(node->node_id == id) break; \
    } \
    if(!node) { \
	printf(" WARNING! : No define router %d\n",id); \
	return; \
    }\
}

struct if_addr *interface_addr();
void pim_recv();
void hello_timeout();
void jp_timeout();
void adv_jp_timeout();
void bsr_timeout();
void adv_bsr_timeout();
void pim_nbr_timeout();
void report_time_out();
void graft_time_out();
void hello_recv_newnbr();
void vif_recv_bootstrap();
void join_prune_recv();
void crp_adv_recv();
void graft_recv();
void graft_ack_recv();
void sg_create_entry();
char *timer_init();
struct dvmrp_nbr *find_dvmrp_nbr();
struct pim_nbr *find_pim_nbr();
struct pim_nbr *choose_pim_dr();
void src_rt_update();
u_long src_nexthop();
struct grp_list *search_grp_list();

extern char *send_buf;
extern char *recv_buf;
extern time_t currnt_time;
extern struct vif *vifs[];
extern char *version[];
extern char *copyright[];
extern struct grp_list *grplist;  /* define in pim.c */

struct NODE *router_list=NULL;
struct GROUP *active_group=NULL;
struct ROUTE *src_net=NULL;     /* routing table from nbrs */
struct sg_entry *sg_table=NULL; /* forwarding cache table */
struct src_entry *src_table=NULL;
int comp_type=0;                /* compare dvmrp packet for "recv" command */
struct bsr_list *bsr_list_head=NULL;
char *recv_timer=NULL;

/*
 *
 */
void router_init(file)
char *file;
{
    int rt;
    char log_file[256];

    if(file)
	strcpy(log_file,file);
    else
	strcpy(log_file,"pimnbr.log");
#if 0
    if(!(rt=log_init(log_file))) {
	printf("log file(%s) can't open \n",log_file);
    }

    log(LOG_INFO,0," \n");
    log(LOG_INFO,0," %s\n",version);
    log(LOG_INFO,0," \n");
/*    log(LOG_INFO,0," %s\n\n",copyright);*/
#endif
    pim_recv_register(PIM_HELLO,hello_recv_newnbr);
    pim_recv_register(PIM_BOOTSTRAP,vif_recv_bootstrap);
    pim_recv_register(PIM_JOIN_PRUNE,join_prune_recv);
    pim_recv_register(PIM_CRP_ADV, crp_adv_recv);
    sg_recv_register(sg_create_entry);

}

#define LIST_ADD(head, node, new)  { \
        if(!head) head = new; \
        else { \
            for(node=head;(node)->next!=NULL;node=(node)->next); \
            (node)->next = new; \
        } \
    }

/*
 *
 */
void router_add(id,addr,interval)
u_long id;
u_long addr;
int interval;
{
    struct NODE *new,*node;
    struct NODE_IF *nif,*new_nif;
    struct pim_data *ps;
    struct if_infp *ifp;
    struct if_addr *ifap;
    int vif;
    u_long net;
    int i;

    if(IS_DEBUG(DEBUG_TRACE))
	log(LOG_INFO,0," TRACE  router add %d %s\n",id,inet_atos(htonl(addr)));

    if(!(ifap = interface_addr(addr))) {
	printf(" WARNING! : interface %s don't exist\n",inet_atos(htonl(addr)));
	return;
    }

    for(node=router_list;node!=NULL;node=node->next) {
	if(node->node_id == id) break;
    }

    if(!node) {
	MALLOC(new, NODE);
	new->node_id = id;
	new_nif = &new->ifaddr;
	new->trace_fp = NULL;
	new->trace_file = NULL;
	LIST_ADD(router_list,node,new);
    }
    else {
	for(nif=&node->ifaddr;nif->next!=NULL;nif=nif->next) ;
	MALLOC(new_nif, NODE_IF);
	nif->next = new_nif;
    }

    new_nif->local_addr = addr;
    new_nif->remote_addr = 0;
    new_nif->ifa = ifap;
    new_nif->protocol = IPPROTO_PIM;
    MALLOC(ps,pim_data);
    new_nif->if_ps = (char *)ps;
    new_nif->state = UP;

    ps->node = new;
    ps->opt_type = HELLO_HOLDTIME;
    ps->opt_len = HELLO_HOLDTIME_LEN;
    ps->opt_val = DEFAULT_HOLDTIME;

    ps->hello_time = interval;
    ps->htimer = timer_init(id,new_nif->if_ps,hello_timeout);
    ps->jp_time = PIM_JOIN_PRUNE_PERIOD;
    ps->jptimer = timer_init(id,new_nif->if_ps,jp_timeout);
    ps->ntimer = timer_init(id,new_nif->if_ps,pim_nbr_timeout);
    ps->bsr_period= 0;
    ps->bsrtimer = NULL;
    ps->adv_bsr = ps->adv_crp = ps->adv_jp = NULL;

#if 1
    if((vif = vif_withaddr(addr)) < 0)
	printf(" No vif %d %s\n",vif,inetaddr_to_char(htonl(addr)));
    else 
	ps->vifs = vif;
#endif
    ps->bsrs = NULL;
    ps->state = DOWN;

}

/*
 *
 */
void router_update_hello(id,type,len,val)
u_long id;
u_short type;
u_short len;
u_long val;
{
    struct NODE *node;
    struct NODE_IF *nif;
    struct pim_data *ps;
    struct if_infp *ifp;
    struct if_addr *ifap;

    if(IS_DEBUG(DEBUG_TRACE))
      log(LOG_DEBUG,0," TRACE router update hello %d \n",id);

    NODE_SEARCH(node,id);

    nif = &node->ifaddr;
    ps = (struct pim_data *)nif->if_ps;

    ps->opt_type = type;
    ps->opt_len = len;
    ps->opt_val = val;

    if(node->trace_fp) {
	trace(node->trace_fp," update hello-option <%d %d %d>\n",type,len,val);
    }

}

/* 
 *
 */
void router_update_hellointerval(id,interval)
u_long id;
int interval;
{
    struct NODE *node;
    struct NODE_IF *nif;
    struct pim_data *ps;
    struct if_infp *ifp;
    struct if_addr *ifap;

    if(IS_DEBUG(DEBUG_TRACE))
      log(LOG_DEBUG,0," TRACE router update hello %d \n",id);

    NODE_SEARCH(node,id);

    nif = &node->ifaddr;
    ps = (struct pim_data *)nif->if_ps;

    ps->hello_time = interval;
    if(ps->state == UP) {
	timer_set(ps->htimer,interval);
    }

    if(node->trace_fp) {
	trace(node->trace_fp," update hello-interval %d \n",interval);
    }


}

/*
 *
 */
void router_bsr(id,pri,period)
u_long id;
int pri;
int period;
{
    struct NODE *node;
    struct NODE_IF *nif;
    struct pim_data *ps;
    int len;

    if(IS_DEBUG(DEBUG_TRACE))
      log(LOG_DEBUG,0," TRACE router bsr %d <pri %d, period %d>\n",id,pri,period);
 
    NODE_SEARCH(node,id);

    nif = &node->ifaddr;
    ps = (struct pim_data *)nif->if_ps;
    ps->bsr_pri = pri;
    ps->bsr_period = period;
    if(ps->bsrtimer) {
	if(ps->state == UP)
	    timer_set(ps->bsrtimer,period);
    }
    else {
	ps->bsrtimer = timer_init(id,nif->if_ps,bsr_timeout);
	if(ps->state == UP)
	    timer_set(ps->bsrtimer,30);
    }
#if 0
    len = pimsm_bsr_send(IF_NAME(nif->ifa),nif->local_addr,ALL_PIM_ROUTERS,nif->local_addr,ps->bsr_pri);
    pim_trace(NULL,htonl(nif->local_addr),htonl(ALL_PIM_ROUTERS), PIM_PKT,len);

    if(node->trace_fp)
	pim_trace(node->trace_fp,htonl(nif->local_addr),htonl(ALL_PIM_ROUTERS),PIM_PKT,len);
#endif

}

/*
 *
 */
void router_adv_bsr(id,adv_list,period)
int id;
int adv_list;
int period;
{
    struct NODE *node;
    struct NODE_IF *nif;
    struct pim_data *ps;
    int len;

    if(IS_DEBUG(DEBUG_TRACE))
      log(LOG_DEBUG,0," TRACE router adv_bsr %d <list %d, period %d>\n",id,adv_list,period);
 
    NODE_SEARCH(node,id);

    nif = &node->ifaddr;
    ps = (struct pim_data *)nif->if_ps;
    ps->adv_bsr_list = adv_list;
    ps->bsr_period = period;

    if(ps->adv_bsr) {
	if(ps->state == UP && period)
	    timer_set(ps->adv_bsr,period);
    }
    else {
	ps->adv_bsr = timer_init(id,nif->if_ps,adv_bsr_timeout);
	if(ps->state == UP && period)
	    timer_set(ps->adv_bsr,period);
    }

    if(ps->state == UP) {
	len = pim_adv_bsr(IF_NAME(nif->ifa),nif->local_addr,ALL_PIM_ROUTERS,ps->adv_bsr_list);
/*	if(len)
	    pim_trace(NULL,htonl(nif->local_addr),htonl(ALL_PIM_ROUTERS), PIM_PKT,len);*/

	if(node->trace_fp)
	    pim_trace(node->trace_fp,htonl(nif->local_addr),htonl(ALL_PIM_ROUTERS),PIM_PKT,len);
    }

}

/*
 *
 */
void router_adv_crpadv(id,adv_list,period)
int id;
int adv_list;
int period;
{
    struct NODE *node;
    struct NODE_IF *nif;
    struct pim_data *ps;
    int len;

    if(IS_DEBUG(DEBUG_TRACE))
      log(LOG_DEBUG,0," TRACE router adv_bsr %d <list %d, period %d>\n",id,adv_list,period);
 
    NODE_SEARCH(node,id);

    nif = &node->ifaddr;
    ps = (struct pim_data *)nif->if_ps;
    ps->adv_bsr_list = adv_list;
    ps->bsr_period = period;

    if(ps->adv_bsr) {
	if(ps->state == UP && period)
	    timer_set(ps->adv_bsr,period);
    }
    else {
	ps->adv_bsr = timer_init(id,nif->if_ps,adv_bsr_timeout);
	if(ps->state == UP && period)
	    timer_set(ps->adv_bsr,period);
    }

    if(ps->state == UP) {
	len = pim_adv_bsr(IF_NAME(nif->ifa),nif->local_addr,ALL_PIM_ROUTERS,ps->adv_bsr_list);
	/*if(len)
	    pim_trace(NULL,htonl(nif->local_addr),htonl(ALL_PIM_ROUTERS), PIM_PKT,len);*/

	if(node->trace_fp)
	    pim_trace(node->trace_fp,htonl(nif->local_addr),htonl(ALL_PIM_ROUTERS),PIM_PKT,len);
    }

}

/*
 *
 */
void router_adv_jp(id,adv_list,period)
int id;
int adv_list;
int period;
{
    struct NODE *node;
    struct NODE_IF *nif;
    struct pim_data *ps;
    int len;

    if(IS_DEBUG(DEBUG_TRACE))
	log(LOG_DEBUG,0," TRACE router adv_jp %d <list %d, period %d>\n",id,adv_list,period);
 
    NODE_SEARCH(node,id);

    nif = &node->ifaddr;
    ps = (struct pim_data *)nif->if_ps;
    ps->adv_jp_list = adv_list;
    ps->jp_time = period;

    if(ps->adv_jp) {
	if(ps->state == UP && period)
	    timer_set(ps->adv_jp,period);
    }
    else {
	ps->adv_jp = timer_init(id,nif->if_ps,adv_jp_timeout);
	if(ps->state == UP && period)
	    timer_set(ps->adv_jp,period);
    }

    if(ps->state == UP) {
	len = pim_adv_jp(IF_NAME(nif->ifa),nif->local_addr,ALL_PIM_ROUTERS,ps->adv_jp_list);
	/*if(len)
	    pim_trace(NULL,htonl(nif->local_addr),htonl(ALL_PIM_ROUTERS), PIM_PKT,len);*/

	if(node->trace_fp)
	    pim_trace(node->trace_fp,htonl(nif->local_addr),htonl(ALL_PIM_ROUTERS),PIM_PKT,len);
    }

}

#define ADD_NBR_LIST(list,nbr)  \
	for(nbr_list=list;nbr_list->next!=NULL;nbr_list=list->next); \
        nbr_list->next = nbr
		 
/*
 *
 */
void router_up(id)
u_long id;
{
    struct NODE *node;
    struct NODE_IF *nif,*nif2;
    struct pim_data *ps,*ps2;
    struct pim_nbr *n,*n2,*nbr_list,*dr;
    int vif;
    int len;
    u_long dst;
#if 0
    if(IS_DEBUG(DEBUG_TRACE))
	log(LOG_INFO,0," TRACE router up %d \n",id);
#endif
    NODE_SEARCH(node,id);

    nif=&node->ifaddr;
    ps = (struct pim_data *)nif->if_ps;
    timer_set(ps->htimer,ps->hello_time);
    ps->state = UP;

    if(ps->bsrtimer && ps->bsr_period) 
	timer_set(ps->bsrtimer,30);

    dst = (nif->remote_addr ? nif->remote_addr : ALL_PIM_ROUTERS);
    len = pim_hello_send(IF_NAME(nif->ifa),nif->local_addr,dst,ps->opt_type,ps->opt_len,ps->opt_val);
	
    if(node->trace_fp) {
	trace(node->trace_fp," router up \n");
	pim_trace(node->trace_fp,htonl(nif->local_addr),htonl(dst),PIM_PKT,len);
    }

    /* add I to other router */
    for(node=router_list;node!=NULL;node=node->next) {
	if(node->node_id == id) continue;

	nif2 = &(node->ifaddr);
	ps2 = (struct pim_data *)nif2->if_ps;

	if(ps->vifs != ps2->vifs) 
	    continue;

	if(ps2->state == DOWN)
	    continue;
	log(LOG_INFO,0," nbr %d %s\n",node->node_id,inetaddr_to_char(htonl(nif->local_addr)));

	MALLOC(n,pim_nbr);
	n->addr = IF_ADDR(nif->ifa);
	n->opt_type = ps->opt_type;
	n->opt_len = ps->opt_len;
	n->opt_val = ps->opt_val;

	if(ps2->nbrs) {
	    if(find_pim_nbr(ps2->nbrs,IF_ADDR(nif->ifa)) == NULL) {
		/* Add New Neighbor */
	        if(IS_DEBUG(DEBUG_TRACE))
		    log(LOG_DEBUG,0," Add New Nighbor %d\n",node->node_id);
		ADD_NBR_LIST(ps2->nbrs,n);
	    }
	}
	else {  /* Add First Neighbor */
	    if(IS_DEBUG(DEBUG_TRACE))
		log(LOG_DEBUG,0," TRACE Add First Nighbor %d\n",node->node_id);
	    ps2->nbrs = n;
	}

	MALLOC(n2,pim_nbr);
	n2->addr = IF_ADDR(nif2->ifa);
	n2->opt_type = ps2->opt_type;
	n2->opt_len = ps2->opt_len;
	n2->opt_val = ps2->opt_val;

	if (ps->nbrs) {
	    ADD_NBR_LIST(ps->nbrs,n2);
	}
        else {
	    if(IS_DEBUG(DEBUG_TRACE))
		log(LOG_INFO,0," First Add to My list %d\n",node->node_id);
	    ps->nbrs = n2;
	}

    } /* router_list */

    /* If I have neighbors , choose DR */
    if(ps->nbrs) {
	/* TODO */
    }
}

/*
 *
 */
void router_down(id)
u_long id;
{
    struct NODE *node;
    struct NODE_IF *nif,*nif2;
    struct pim_data *ps,*ps2;
    struct pim_nbr *n,*nbr_list,*prev;
    int vif;
    int len;
    struct ROUTE *rtp;

    if(IS_DEBUG(DEBUG_TRACE))
	log(LOG_INFO,0," TRACE router down %d \n",id);

    NODE_SEARCH(node,id);

    nif=&node->ifaddr;
    ps = (struct pim_data *)nif->if_ps;
    timer_stop(ps->htimer);
    ps->state = DOWN;

    if(node->trace_fp)
	trace(node->trace_fp," router down \n");

    /* delete I from other router */
    for(node=router_list;node!=NULL;node=node->next) {
	if(node->node_id == id) continue;

	nif2 = &(node->ifaddr);
	ps2 = (struct pim_data *)nif2->if_ps;

	if(ps->vifs != ps2->vifs) 
	    continue;

	if(ps2->state == DOWN)
	    continue;

	if(ps2->nbrs) {
	    prev = NULL;
	    for(nbr_list=ps2->nbrs;nbr_list;nbr_list=nbr_list->next) {
		if(nbr_list->addr == nif->local_addr) {
		    if(prev) prev->next = nbr_list->next;
		    else {
			if(nbr_list->next)
			    ps2->nbrs = nbr_list->next;
			else
			    ps2->nbrs = NULL;
		    }
		    free(nbr_list);
		    break;
		}
		prev = nbr_list;
	    } /* for */
	}

    } /* router_list */

    /* Delete nbr from out list */
    if(ps->nbrs) {  
	for(nbr_list=ps->nbrs;nbr_list!=NULL;) {
	    nbr_list = nbr_list->next;
	    if(nbr_list) free(nbr_list);
	}
	ps->nbrs = NULL;
    }

}

/*
 *
 */
void hello_timeout(id,data)
u_long id;
char *data;
{
    struct NODE *node;
    struct NODE_IF *nif;
    struct pim_data *ps;
    int len;
    u_long dst;

    if(IS_DEBUG(DEBUG_TIMER))
	log(LOG_INFO,0," TIMER pim hello_timeout %d \n",id);    

    NODE_SEARCH(node,id);

    nif = &node->ifaddr;
    ps = (struct pim_data *)data;

    dst = (nif->remote_addr ? nif->remote_addr : ALL_PIM_ROUTERS);
    len = pim_hello_send(IF_NAME(nif->ifa),nif->local_addr,dst,ps->opt_type,ps->opt_len,ps->opt_val);
    /* pim_trace(NULL,htonl(nif->local_addr),htonl(dst), PIM_PKT,len);*/

    if(node->trace_fp)
	pim_trace(node->trace_fp,htonl(nif->local_addr),htonl(dst),PIM_PKT,len);
	
}

/*
 *
 */
void jp_timeout(id,data)
u_long id;
char *data;
{
    struct NODE *node;
    struct NODE_IF *nif;
    struct pim_data *ps;
    int len;
    u_long dst,upstream;
    struct sg_entry *sgp;

    if(IS_DEBUG(DEBUG_TIMER))
	log(LOG_INFO,0," TIMER pim jp_timeout %d \n",id);    

    NODE_SEARCH(node,id);

    nif = &node->ifaddr;
    ps = (struct pim_data *)data;
    if(nif->remote_addr) dst = nif->remote_addr;
    else dst = ALL_PIM_ROUTERS;

    for(sgp=sg_table;sgp != NULL; sgp=sgp->next) {
	upstream = sgp->upstream;
    }
    len = pimsm_jp_send2(IF_NAME(nif->ifa),nif->local_addr,dst,upstream,PIM_JOIN_PRUNE_HOLDTIME,0);

    if(node->trace_fp)
	pim_trace(node->trace_fp,htonl(nif->local_addr),htonl(dst),PIM_PKT,len);
	
}

/*
 *
 */
void adv_jp_timeout(id,data)
u_long id;
char *data;
{
    struct NODE *node;
    struct NODE_IF *nif;
    struct pim_data *ps;
    int len;
    u_long dst;

    if(IS_DEBUG(DEBUG_TIMER))
	log(LOG_INFO,0," TIMER pim adv_jp_timeout %d <data %x>\n",id,data);   

    NODE_SEARCH(node,id);

    nif = &node->ifaddr;
    ps = (struct pim_data *)nif->if_ps;

    dst = (nif->remote_addr ? nif->remote_addr : ALL_PIM_ROUTERS);
    len = pim_adv_jp(IF_NAME(nif->ifa),nif->local_addr,dst,ps->adv_jp_list);

    if(node->trace_fp)
	pim_trace(node->trace_fp,htonl(nif->local_addr),htonl(dst),PIM_PKT,len);

}

/*
 *
 */
void bsr_timeout(id,data)
u_long id;
char *data;
{
    struct NODE *node;
    struct NODE_IF *nif;
    struct pim_data *ps;
    int len;
    u_long dst;

    if(IS_DEBUG(DEBUG_TIMER))
	log(LOG_INFO,0," TIMER pim bsr_timeout %d <data %x>\n",id,data);    

    NODE_SEARCH(node,id);

    nif = &node->ifaddr;
    ps = (struct pim_data *)nif->if_ps;

    dst = (nif->remote_addr ? nif->remote_addr : ALL_PIM_ROUTERS);
    len = pimsm_bsr_send(IF_NAME(nif->ifa),nif->local_addr,dst,nif->local_addr,ps->bsr_pri);

    if(node->trace_fp)
	pim_trace(node->trace_fp,htonl(nif->local_addr),htonl(dst),PIM_PKT,len);

    timer_set(ps->bsrtimer,ps->bsr_period);
}

/*
 *
 */
void adv_bsr_timeout(id,data)
u_long id;
char *data;
{
    struct NODE *node;
    struct NODE_IF *nif;
    struct pim_data *ps;
    int len;
    u_long dst;

    if(IS_DEBUG(DEBUG_TIMER))
	log(LOG_INFO,0," TIMER pim adv_bsr_time_ut %d <data %x>\n",id,data);  

    NODE_SEARCH(node,id);

    nif = &node->ifaddr;
    ps = (struct pim_data *)nif->if_ps;

    dst = (nif->remote_addr ? nif->remote_addr : ALL_PIM_ROUTERS);
    len = pim_adv_bsr(IF_NAME(nif->ifa),nif->local_addr,dst,ps->adv_bsr_list);

    if(node->trace_fp)
	pim_trace(node->trace_fp,htonl(nif->local_addr),htonl(dst),PIM_PKT,len);

}

/*
 *
 */
void router_add_bsr(bsr_addr,bsr_pri,rpset)
u_long bsr_addr;
u_long bsr_pri;
int rpset;
{
    struct bsr_list *bsrp,*new;
    struct grp_list *new_grp,*gp;
    struct rp_list *rp;

    MALLOC(new, bsr_list);
    new->bsr_addr = bsr_addr;
    new->priority = bsr_pri;
    new->rp = NULL;
    new->grp = NULL;

    LIST_ADD(bsr_list_head, bsrp, new);

}

/*
 *
 */
void pim_nbr_timeout(id,data)
u_long id;
char *data;
{
    struct NODE *node;
    struct NODE_IF *nif;
    struct pim_data *ps;
    struct pim_nbr *nbr;
    int len;
    struct ROUTE *src;

    if(IS_DEBUG(DEBUG_TIMER))
        log(LOG_DEBUG,0," TIMER nbr_timeout %d \n",id);    

    NODE_SEARCH(node,id);

    nif = &node->ifaddr;
    ps = (struct pim_data *)data;
    for(nbr=ps->nbrs;nbr;nbr=nbr->next) {
        if(nbr->state == DOWN) continue;
        if(currnt_time - nbr->recv_time > nbr->opt_val) {
            log(LOG_INFO,0," Neighbor %s Down \n",inet_atos(htonl(nbr->addr)));
            nbr->state = DOWN;
            ps->nbr_count--;
        }

    }

}

/*
 *
 */
void recv_timeout(id,data)
u_long id;
char *data;
{
    timer_stop(recv_timer);
    if(comp_type) {
	printf("   Timeout Receive Packet \n");
	log(LOG_INFO,0,"     Timeout Receive Packet \n");
	comp_type = 0;
    }
}

/*
 *
 */
void check_pim_packet(src,dst,type,packet,pkt_len)
u_long src,dst;
int type;
char *packet;
int pkt_len;
{
    if(type == comp_type) {
	pim_comp_register(NULL);
	comp_type = 0;
	wait_timeout(0,NULL);
	printf(" Packet Receive <type %d>\n",type);
	log(LOG_INFO,0," Packet Receive <type %d> (Match)\n",type);
    }
    else {
	printf(" Packet Receive <type %d>\n",type);
	log(LOG_INFO,0," Packet Receive <type %d> (Mismatch)\n",type);
    }
}

/*
 *
 */
void comp_packet_recv(type,timeout)
int type;
int timeout;
{
    comp_type = type;
    pim_comp_register(check_pim_packet);
    if(!recv_timer)
	recv_timer = timer_init(0,NULL,recv_timeout);
    timer_set(recv_timer,timeout);
}

/*
 *
 */
int member_search(list, group)
struct member *list;
u_long group;
{
    struct member *mem;

    for(mem=list;mem!=NULL;mem=mem->next) {
	if(mem->group == group)
	    return 1;
    }

    return 0;
}

/*
 *
 */
u_long source_locate(addr)
u_long addr;
{
    struct ROUTE *rt;

    for(rt=src_net;rt!=NULL;rt=rt->next) {
	if(rt->addr == (addr & rt->mask)) 
	    return rt->gateway;
    }
    return 0;
}

/*
 *
 */
void hello_recv_newnbr(vif,src,dst,nbr,pim,pim_len)
int vif;
u_long src,dst;
struct pim_nbr *nbr;
struct pim_header *pim;
int pim_len;
{
    struct NODE *node;
    struct NODE_IF *nif;
    struct pim_data *ps;
    u_long *dvmrp,rt;
    struct pim_nbr *nbr_list,*n;
    char *hello;
    int nbr_change;
    int len,rlen;

    if(IS_DEBUG(DEBUG_TRACE))
	log(LOG_INFO,0," TRACE hello_recv_newnbr %s\n",inet_atos(htonl(nbr->addr)));

    for(node=router_list;node!=NULL;node=node->next) {

        hello = (char *)(pim+1);
	nbr_change=0;
	nif = &(node->ifaddr);
	ps = (struct pim_data *)nif->if_ps;

	if(vif != ps->vifs) 
	    continue;

	if(ps->state == DOWN)
	    continue;

	if(nif->local_addr == src)
	    continue;

	if(node->trace_fp) 
	    pim_trace(node->trace_fp,htonl(src),htonl(dst),pim,pim_len);

	if(ps->nbrs) {
	    n = find_pim_nbr(ps->nbrs,nbr->addr);
	    if(n) {
		if(n->state == UP) nbr_change++;
		else if(n->state == DOWN) {
		    nbr_change++;
		    ps->nbr_count++;
		    n->state = UP;
		}
		n->recv_time = currnt_time;
	    }
	    else { /* Add New Neighbor */
		if(IS_DEBUG(DEBUG_TRACE))
		    log(LOG_INFO,0," TRACE ADD new nbr to %d\n",node->node_id);
		MALLOC(n,pim_nbr);
		n->addr = nbr->addr;
		n->state = UP;
		GET_SHORT(n->opt_type,hello);
		GET_SHORT(n->opt_len,hello);
		if(n->opt_type == HELLO_HOLDTIME)
		    GET_SHORT(n->opt_val,hello);
		n->recv_time = currnt_time;
		nbr_change++;
		ADD_NBR_LIST(ps->nbrs,n);
		ps->nbr_count++;
		timer_set(ps->ntimer,5);
	    }
	}
	else {  /* Add First Neighbor */
	    if(IS_DEBUG(DEBUG_TRACE))
		log(LOG_DEBUG,0," TRACE ADD First nbr %d\n",node->node_id);
	    MALLOC(n,pim_nbr);
	    ps->nbrs = n;
	    n->addr = nbr->addr;
	    n->state = UP;
	    GET_SHORT(n->opt_type, hello);
	    GET_SHORT(n->opt_len,hello);
	    if(n->opt_type == HELLO_HOLDTIME)
	        GET_SHORT(n->opt_val,hello);
	    n->recv_time = currnt_time;
	    nbr_change++;
	    ps->nbr_count++;
	    timer_set(ps->ntimer,5);
	}
    } /* router_list */
}

/*
 *
 */
void node_recv_bootstrap(node,pim,pim_len)
struct NODE *node;
struct pim_header *pim;
int pim_len;
{

    struct NODE_IF *nif;
    struct pim_data *ps;
    struct bsr_list *bsr,*list;
    u_long *dvmrp,rt;
    int nbr_change;
    int len,rlen;
    u_short fragtag,holdtime;
    u_char hmlen,bsrpri;
    struct in_addr bsraddr;
    struct pim_euaddr eu;
    struct in_addr gaddr,gmask,saddr;
    struct pim_eaddr egrp;
    u_char           *cp = (char *) (pim + 1);
    char nrp,nfrag;
    u_char pri;
    struct grp_list *grp;

    if(IS_DEBUG(DEBUG_TRACE))
	log(LOG_INFO,0," TRACE node_recv_bootstarp %d\n",node->node_id);

    nif = &(node->ifaddr);
    ps = (struct pim_data *)nif->if_ps;

    GET_SHORT(fragtag, cp);
    hmlen = *cp++;
    bsrpri = *cp++;
    
    GET_EUADDR_SOCK((struct pim_euaddr *)&eu, bsraddr, cp);
    if(eu.eu_family != 1 || !bsraddr.s_addr) {
	printf("\t bootstrap: bad group family %d\n",eu.eu_family);
	return;
    }
    
    MALLOC(bsr,bsr_list);
    bsraddr.s_addr = ntohl(bsraddr.s_addr);
    bsr->bsr_addr = bsraddr.s_addr;
    bsr->frag_tag = fragtag;
    bsr->hashmask = hmlen;
    bsr->priority = bsrpri;

    if(ps->bsrs) {
	for(list=ps->bsrs;list;list=list->next) {
	    if(list->bsr_addr == bsraddr.s_addr)
		break;
	    else 
		if(IS_DEBUG(DEBUG_TRACE))
		    log(LOG_INFO,0," TRACE ADD New BSR %s\n",inetaddr_to_char(htonl(bsr->bsr_addr)));
	}
	    
    }
    else {  /* Add First BSR */
	if(IS_DEBUG(DEBUG_TRACE))
	    log(LOG_INFO,0," TRACE ADD First BSR %s\n",inetaddr_to_char(htonl(bsr->bsr_addr)));
	ps->bsrs = bsr;
    }

    /* get CRP's information */
    while((char *)pim + pim_len > (char *)cp) {

	GET_EADDR_SOCK((struct pim_eaddr *)&egrp,gaddr,gmask,cp);
	if(!gaddr.s_addr)
	    return;

	/* group_list search */
	grp = search_grp_list(ntohl(gaddr.s_addr),gmask.s_addr);
	if(!grp) {
	    MALLOC(grp,grp_list);
	    grp->addr = ntohl(gaddr.s_addr);
	    grp->mask = gmask.s_addr;
	    add_grp_list(grp->addr,grp->mask);
	}
	nrp = *cp++;
	nfrag = *cp++;
	*cp++;
	*cp++;

	while(nrp--) {
	    
	    GET_EUADDR_SOCK((struct pim_euaddr *)&eu, saddr, cp);
	    if(eu.eu_family != 1 || !saddr.s_addr) {
		printf("\t bootstrap: bad group family %d\n",eu.eu_family);
		return;
	    }

	    GET_SHORT(holdtime, cp);
	    pri = *cp++;
	    *cp++;  /* reserved */

	    add_rpset_list2(0,grp->addr,grp->mask,ntohl(saddr.s_addr),holdtime,pri);
	}
    }
}

/*
 *
 */
void vif_recv_bootstrap(vif,src,dst,pim,pim_len)
int vif;
u_long src,dst;
struct pim_header *pim;
int pim_len;
{
    struct NODE *node;
    struct NODE_IF *nif;
    struct pim_data *ps;
    u_long *dvmrp,rt;
    int nbr_change;
    int len,rlen;

    if(IS_DEBUG(DEBUG_TRACE))
	log(LOG_INFO,0," TRACE vif_recv_bootstarp \n");

    if(dst != ALL_PIM_ROUTERS) {
	for(node=router_list;node!=NULL;node=node->next) {
	    if(node->trace_fp) 
		pim_trace(node->trace_fp,htonl(src),htonl(dst),pim,pim_len);

	    nif = &(node->ifaddr);
	    ps = (struct pim_data *)nif->if_ps;
	    if(dst == nif->local_addr && ps->state == UP)
		node_recv_bootstrap(node,pim,pim_len);
	}
	return;
    }

    for(node=router_list;node!=NULL;node=node->next) {
	if(node->trace_fp) 
	    pim_trace(node->trace_fp,htonl(src),htonl(dst),pim,pim_len);

	nif = &(node->ifaddr);
	ps = (struct pim_data *)nif->if_ps;

	if(vif != ps->vifs) 
	    continue;

	if(ps->state == DOWN)
	    continue;
	
	node_recv_bootstrap(node,pim,pim_len);

    } /* router_list */
}

/*
 *
 */
void join_prune_recv(vif,src,dst,pim,pim_len)
int vif;
u_long src,dst;
struct pim_header *pim;
int pim_len;
{
    /* TODO */
}

/*
 *
 */
void crp_adv_recv(vif,src,dst,pim,pim_len)
int vif;
u_long src,dst;
struct pim_header *pim;
int pim_len;
{
    /* TODO */
}

/*
 *
 */
void sg_create_entry(src,dst)
u_long src,dst;
{
    int iif;
    struct sg_entry *new_sg,*sgp;
    struct NODE *node;
    struct NODE_IF *nif;
    struct pim_data *ps;
    u_long upstream,rp;

    log(LOG_INFO,0," sg_create_entry (%s,%s)\n",
	inetaddr_to_char(htonl(src)),inet_atos(htonl(dst)));

    if(src) {
	upstream = src_nexthop(src);
    }
    else {
	rp = search_crp_withgrp(dst,0xffffffff);
	if(!rp) {
	    printf("Not found rpf information for (*,%s)\n",inet_atos(htonl(dst)));
	    return;
	}
	upstream = src_nexthop(rp);
    }
    if(upstream) 
	iif = vif_withaddr(upstream);
    else
	/* Check src is on direct network */
	iif = vif_withaddr(src);
    log(LOG_INFO,0," sg previous_hop %s iif %d\n",inet_atos(htonl(upstream)),iif);
    if(iif<0) 
        return;

    MALLOC(new_sg, sg_entry);
    if(sg_table) {
	for(sgp=sg_table;sgp->next!=NULL;sgp=sgp->next);
	sgp->next = new_sg;
    }
    else {
	sg_table = new_sg;
    }
    new_sg->src = src;
    new_sg->group = dst;
    new_sg->iif = iif;
    new_sg->upstream = upstream;

    if(!src)
	return ;  /* create (*,G) */

    kernel_add_entry(htonl(src),htonl(dst),iif);

}

/*
 *
 */
void member_add(id,grp)
u_long id,grp;
{
    struct member *mem,*new_mem;
    struct NODE *node;
    struct NODE_IF *nif;
    struct pim_data *ps;
    struct prune_list *prn;
    u_long crp_addr,upstream;
    int len;

    log(LOG_INFO,0," member_add %d %s\n",id,inet_atos(htonl(grp)));

    for(node=router_list;node!=NULL;node=node->next) {
	if(node->node_id == id) break;
    }

    if(!node) {
	return;
    }

    nif = &node->ifaddr;
    ps = (struct pim_data *)nif->if_ps;
    for(mem=ps->member_list;mem!=NULL;mem=mem->next) {
      if(mem->group == grp) {
	printf(" Already Have member \n");
	    return;
      }
    }
    
    /* Add member per router */
    MALLOC(new_mem,member);
    new_mem->group = grp;
    if(ps->member_list) {
	for(mem=ps->member_list;mem->next!=NULL;mem=mem->next);
	if(mem) mem->next = new_mem;
    }
    else {
	ps->member_list = new_mem;
	timer_set(ps->jptimer,ps->jp_time);
    }

    /* add_jp_entry(grp,0xffffffff);*/
    add_jp_list(0,grp,0xffffffff); 
    crp_addr = search_crp_withgrp(grp,0xffffffff);
    if(!crp_addr) {
	printf(" No C-RP information for %s\n",inet_atos(htonl(grp)));
        return ;
    }
    /*add_jp_join_list(grp,crp_addr,0xffffffff,0x7);*/
    add_jp_join_list2(0,grp,crp_addr,0xffffffff,0x7);
    upstream = src_nexthop(crp_addr);
    if(!upstream) {
	printf(" Not found upstream neighbor for %s\n", inet_atos(htonl(crp_addr)));
	return;
    }
    add_jp_list_nbr(0,upstream,210);
    len = pimsm_jp_send2(IF_NAME(nif->ifa),0,ALL_PIM_ROUTERS,upstream,210,0);

    if(node->trace_fp) {
	trace2(node->trace_fp," member add %s\n",inet_atos(htonl(grp)));
	pim_trace(node->trace_fp,htonl(nif->local_addr),htonl(ALL_PIM_ROUTERS),PIM_PKT,len);
    }
    sg_create_entry(INADDR_ANY_SRC,grp);
}

/*
 *
 */
void member_delete(id,grp)
u_long id,grp;
{
    struct member *mem,*prev;
    struct NODE *node;
    struct NODE_IF *nif;
    struct pim_data *ps;
    struct sg_entry *sgp;
    u_long bsr_addr,crp_addr;
    int len;

    if(IS_DEBUG(DEBUG_TRACE))
	log(LOG_INFO,0," member_delete %d %s\n",id,inet_atos(htonl(grp)));

    for(node=router_list;node!=NULL;node=node->next) {
	if(node->node_id == id) break;
    }

    if(!node) {
	return;
    }

    nif = &node->ifaddr;
    ps = (struct pim_data *)nif->if_ps;
    prev = NULL;

    /*add_jp_entry(grp,0xffffffff);*/
    add_jp_list(0,grp,0xffffffff);
    crp_addr = search_crp_withgrp(grp,0xffffffff);
    /* add_jp_prune_list(grp,crp_addr,0xffffffff,0x7);*/
    add_jp_prune_list2(0,grp,crp_addr,0xffffffff,0x7);
    bsr_addr = ps->bsrs->bsr_addr;
    len = pimsm_jp_send2(IF_NAME(nif->ifa),0,ALL_PIM_ROUTERS,bsr_addr,210,0);
    pim_trace(NULL,htonl(nif->local_addr),htonl(ALL_PIM_ROUTERS),PIM_PKT,len);
    if(node->trace_fp) {
	trace2(node->trace_fp," member delete %s\n",inet_atos(htonl(grp)));
	pim_trace(node->trace_fp,htonl(nif->local_addr),htonl(ALL_PIM_ROUTERS),PIM_PKT,len);
    }
}

/*
 *
 */
void add_src_net(net,mask,nexthop) 
u_long net;
u_long mask;
u_long nexthop;
{
    struct ROUTE *rtp,*new;

    if(src_net) {
	for(rtp=src_net;rtp->next!=NULL;rtp=rtp->next) {
	  if(rtp->addr == net
	  && rtp->mask == mask
	  && rtp->gateway == nexthop) {
	    log(LOG_INFO,0," route exist \n");
	    return;
	  }
	}
	MALLOC(new,ROUTE);
	rtp->next = new;
    }
    else {
	MALLOC(new,ROUTE);
	src_net = new;
    }
    new->addr = net;
    new->mask = mask;
    new->metric = 0;
    new->gateway = nexthop;
}

/*
 *
 */
void src_rt_update(rt,nexthop)
struct ROUTE *rt;
u_long nexthop;
{
    struct ROUTE *new,*rtp;
    
    log(LOG_INFO,0," src_rt_update %s\n",inetaddr_to_char(htonl(rt->addr)));

    if(src_net) {
	for(rtp=src_net;rtp->next!=NULL;rtp=rtp->next) {
	  if(rtp->addr == rt->addr
	  && rtp->mask == rt->mask
	  && rtp->metric == rt->metric
	  && rtp->gateway == nexthop) {
	    log(LOG_INFO,0," route exist \n");
	    return;
	  }
	}
	MALLOC(new, ROUTE);
	rtp->next = new;
    }
    else {
	MALLOC(new, ROUTE);
	src_net = new;
    }
    new->addr = rt->addr;
    new->mask = rt->mask;
    new->metric = rt->metric;
    new->gateway = nexthop;
}

/*
 *
 */
u_long src_nexthop(addr)
u_long addr;
{
    struct ROUTE *rtp;
    int iif;

    /* Search source network from neighbor */
    for(rtp=src_net;rtp!=NULL;rtp=rtp->next) {
      if(rtp->addr == (addr & rtp->mask)) {
	return rtp->gateway;
      }
    }

    return 0;
}

/*
 *
 */
void router_trace(id,file)
u_long id;
char *file;
{
    struct NODE *node;

    NODE_SEARCH(node,id);

    if((node->trace_fp=fopen(file,"w+")) == NULL) {
	printf(" %s can't open \n",file);
    }
    trace(node->trace_fp,"\n %s\n\n",version);
    /*    trace(node->trace_fp," %s\n\n",copyright);*/

}

/*
 *
 */    
void router_dump(id,file)
u_long id;
char *file;
{
    struct NODE *node;
    struct NODE_IF *nif;
    struct pim_data *ps;
    struct network_list *net;
    struct NET_LIST *list;
    struct ROUTE *np;
    struct bsr_list *bsr;
    struct pim_nbr *nbr;
    FILE *fp;
    int len;
    char *state[]={"Down","Up","Dr"};
    struct grp_list *grp;
    struct rp_list *rp;
    struct prune_list *prn;

    if(file) {
	if((fp = fopen(file,"w+")) == NULL) {
	    trace(stderr,"can't open file(%s) \n",file);
	    fp = NULL;
	}
    }
    else {
	fp = NULL;
    }

    NODE_SEARCH(node,id);

    trace(fp,"\n Router %d \n",node->node_id);
    nif = &node->ifaddr;
    trace(fp," \t Addr: %s(%s) \n", 
	       inet_atos(htonl(IF_ADDR(nif->ifa))),IF_NAME(nif->ifa));
    ps = (struct pim_data *)nif->if_ps;
    trace(fp," \t vif: %d ",ps->vifs);
    trace(fp,"    state: %s \n",state[ps->state]);
    trace(fp," \t hello-interval: %d \t hello-holdtime %d\n",
	  ps->opt_val, ps->hello_time);
    if(ps->bsrs) {
	trace(fp," \t BSRs: \n");
	for(bsr=ps->bsrs;bsr;bsr=bsr->next) {
	    trace(fp,"\t  addr: %s  hashmask: %d  priority: %d\n",
		  inet_atos(htonl(bsr->bsr_addr)),bsr->hashmask,bsr->priority);
	}
    }

    if(grplist) {
	trace(fp," \t CRPs: \n");
	for(grp=grplist;grp!=NULL;grp=grp->next) {
	    trace(fp," \t Group: %s",inet_atos(htonl(grp->addr)));
	    trace(fp," /%s RPs: %d\n",inet_atos(htonl(grp->mask)),grp->rp_cnt);
	    for(rp=grp->rp;rp!=NULL;rp=rp->next) {
		trace(fp," \t  Addr: %s  holdtime: %d priority: %d\n",
		      inet_atos(htonl(rp->addr)),rp->holdtime,rp->priority);
	    }
	}
    }
#if 0
    trace(fp," \t : %d.%d \t GenID: %x ", ps->vers & 0x00ff,ps->vers>>8 & 0x00ff,ps->gen_id);
    trace(fp,"    Flags: ");
    if(ps->cap_flag & DVMRP_CAP_LEAF) trace(fp,"Leaf ");
    if(ps->cap_flag & DVMRP_CAP_PRUNE) trace(fp,"Prune ");
    if(ps->cap_flag & DVMRP_CAP_GENID) trace(fp,"Genid ");
    if(ps->cap_flag & DVMRP_CAP_MTRACE) trace(fp,"Mtrace ");
    if(ps->cap_flag & DVMRP_CAP_SNMP) trace(fp,"Snmp ");
    trace(fp,"\n");

/*    for(net=ps->rt_table;net;net=net->next) {
	trace(fp," \t Routes:%s",inetaddr_to_char(htonl(net->addr)));
	trace(fp,"   Mask:%s  Metric:%d \n",inetaddr_to_char(htonl(net->mask)),net->metric);
    }
*/
    trace(fp," \t Routes: \n");
    for(len=0;len<32;len++) {
        for(np=ps->dvmrp_route[len];np;np=np->next) {
	    trace(fp," \t   %-15s ",inetaddr_to_char(htonl(np->addr)));
	    trace(fp,"    mask: %-15s   metric: %d\n",inetaddr_to_char(htonl(np->mask)),np->metric);
	}
    }

    trace(fp," \t Net List: ");
    for(list=ps->nets;list;list=list->next) {
	trace(fp,"%d ",list->id);
    }
#endif

    trace(fp,"\n\t Neighbors:\n");
    for(nbr=ps->nbrs;nbr!=NULL;nbr=nbr->next) {
	trace(fp," \t   %s(%s) \t Option type:%d len:%d val:%d \n",inet_atos(htonl(nbr->addr)),state[nbr->state], nbr->opt_type,nbr->opt_len,nbr->opt_val);
    }
    trace(fp,"\n");

    trace(fp,"\t Prunes:\n");
    for(prn=ps->prunes;prn;prn=prn->next) {
        trace(fp," \t    (%s ,",inet_atos(htonl(prn->src)));
	trace(fp," %s)  %ds", inet_atos(htonl(prn->grp)),prn->lifetime);
	trace(fp," upstream %s \n",inet_atos(htonl(prn->nbr_addr)));
    }
    trace(fp,"\n");
}

/*
 *
 */
void sg_entry_dump()
{
    struct sg_entry *sgp;

    printf("\n (S,G) Entrys: \n");
    if(!sg_table)
	printf(" \t none \n");
    for(sgp=sg_table;sgp!=NULL;sgp=sgp->next) {
	if(sgp->src) 
	    printf(" \t (%s,",inet_atos(htonl(sgp->src)));
	else 
	    printf(" \t (*,");
	printf("%s) ",inet_atos(htonl(sgp->group)));
	printf("  iif:%d   upstream:%s\n",sgp->iif,inet_atos(htonl(sgp->upstream)));
    }
    printf("\n");
}

/*
 *
 */
void src_net_dump()
{
    struct ROUTE *rt;

    printf("\n Source Network \n");
    for(rt=src_net;rt!=NULL;rt=rt->next) {
	printf("\t %s/ ",inetaddr_to_char(htonl(rt->addr)));
	printf("%s ",inetaddr_to_char(htonl(rt->mask)));
	printf(" Previous Hop: %s ",inetaddr_to_char(htonl(rt->gateway)));
	printf(" Metric: %d\n",rt->metric);
    }
    printf("\n");
}

/*
 *
 */
void dump()
{
    struct NODE *node;
    struct NODE_IF *nif;
    struct dvmrp_data *ps;
    struct network_list *net;
    struct dvmrp_nbr *nbr;

    for(node=router_list;node!=NULL;node=node->next) {
        router_dump(node->node_id,NULL);
    }
    vif_dump();
    src_net_dump();
    sg_entry_dump();
    print_jp_list();
#if 0
    network_dump();
#endif
}

void do_report_send(if_name, id)
char *if_name;
u_long id;
{
    struct ROUTE *rt, *get_route_list();

    for(rt=get_route_list(id);rt!=NULL;rt=rt->next) {
/*	add_network_list(rt->addr,rt->mask,rt->metric);*/
    }
/*    dvmrp_report_send(if_name,0,0);*/
}
