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

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

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 FILTER *filtp;
};
    
struct NODE {
    struct NODE *next;
    u_long node_id;
    struct NODE_IF ifaddr;
    FILE *trace_fp;
    char *trace_file;
};

struct igmp_data {
    struct NODE *node;
    struct GROUP *group;
    int query_time;  /* Query Interval */
    int recv_time;   /* Last Report receive time */
    char *qtimer;
    short ver;
    short flag;
};

#define JOIN 1
#define LEAVE 2

struct MEMBER {
    struct MEMBER *next;
    struct NODE *node;
    int state;   /* join or leave */
};

struct GROUP {
    struct GROUP *next;
    u_long grp_addr;
    int mem_num;
    struct MEMBER *member;
};

struct FILTER {
    struct FILTER *next;
    union index {
	u_long id;
	char *ptr;
    };
    int type;
    u_long info;
};

#define FILTER_PKT 1
#define FILTER_SRC 2
#define FILTER_DST 3

#define FILTER_QUERY  0x01
#define FILTER_REPORT 0x02
#define FILTER_LEAVE  0x04

#define NODE_SEARCH(node,id) \
{ \
    for(node=host_list;node!=NULL;node=node->next) { \
	if(node->node_id == id) break; \
    } \
    if(!node) { \
	printf(" WARNING! : No define host %d\n",id); \
	return; \
    }\
}

#ifdef IPOPT_RA
#define IGMP_TRACE(fp) 	igmp_trace(fp,htonl(nif->local_addr),htonl(dst),(struct igmp *)(send_buf+IPHDR_LEN+RA_OPT_LEN))
#else
#define IGMP_TRACE(fp) 	igmp_trace(fp,htonl(nif->local_addr),htonl(dst),(struct igmp *)(send_buf+IPHDR_LEN))
#endif

struct if_addr *interface_addr();
char *inet_atos();
char *timer_init();

void join_host_report();
void join_leave_timeout();
void host_dump();
extern char *send_buf;
extern char *recv_buf;
extern time_t currnt_time;
extern char version[],copyright[];

struct NODE *host_list=NULL;
struct GROUP *active_group=NULL;
struct igmp *compare=NULL;
char *recv_timer=NULL;

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

    if(file) 
	strcpy(log_file,file);
    else
	strcpy(log_file,"mhost.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
    igmp_recv_register(IGMP_MEMBERSHIP_QUERY,join_host_report);
}

/*
 *
 */
void host_add(id,addr,ver)
u_long id;
u_long addr;
short ver;
{
    struct NODE *new_host,*host;
    struct NODE_IF *nif,*new_nif,*p_nif;
    struct igmp_data *ps;
    struct if_addr *ifap;
    char *inet_atos();

#if 1
    if(IS_DEBUG(DEBUG_TRACE))
	log(LOG_DEBUG,0," host-list %d %s\n",id,inet_atos(htonl(addr)));
#endif

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

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

    if(!host) {
	MALLOC(new_host, NODE);
	new_host->node_id = id;
	new_nif = &(new_host->ifaddr);
	new_host->trace_fp = NULL;
	new_host->trace_file = NULL;
    }
    else {
	for(nif=&(host->ifaddr);nif!=NULL;nif=nif->next) {
	    if(nif->local_addr == addr) {
		printf(" already defined host %d addr %s\n",
		       id,inet_atos(htonl(addr)));
		return;
	    }
	    p_nif=nif;
	}
	MALLOC(new_nif,NODE_IF);
	p_nif->next = new_nif;
    }

    new_nif->local_addr = addr;
    new_nif->ifa = ifap;
    new_nif->protocol = IPPROTO_IGMP;

    MALLOC(ps,igmp_data);
    new_nif->if_ps = (char *)ps;
    new_nif->state = UP;
    new_nif->filtp = NULL;

    ps->node = new_host;
    ps->ver = ver;
    ps->group = NULL;

    if(!host_list) host_list = new_host;
    else {
	for(host=host_list;host->next!=NULL;host=host->next);
	host->next = new_host;
    }

    if(IS_DEBUG(DEBUG_TRACE))
	log(LOG_DEBUG,0," New host add %d %s\n",id,inet_atos(htonl(addr)));
}

/*
 *
 */
void join_group(id,group)
u_long id;
u_long group;
{
    struct GROUP *grp,*new_grp,*last;
    struct NODE *host;
    struct NODE_IF *nif;
    struct igmp_data *ps;
    struct MEMBER *mem_list,*new_mem;
    u_long dst=group;

#if 0
    if(IS_DEBUG(DEBUG_TRACE))
	log(LOG_INFO,0," host join %d %s\n",id,inet_atos(htonl(group)));
#endif

    /* Host list */
    NODE_SEARCH(host,id);

    nif = &host->ifaddr;
    ps = (struct igmp_data *)nif->if_ps;
    if(ps->group) {
	for(grp=ps->group;grp;grp=grp->next) {
	    if(grp->grp_addr == group) {
		grp->mem_num = 1;
		break;
	    }
	    last = grp;
	}
	if(!grp) {
	    MALLOC(grp, GROUP);
	    grp->grp_addr = group;
	    grp->mem_num = 1;
	    last->next = grp;
	}
    }
    else {
	MALLOC(ps->group, GROUP);
	ps->group->grp_addr = group;
	ps->group->mem_num = 1;
    }

    if(nif->state == UP) {
	igmp_report_send(IF_NAME(nif->ifa),nif->local_addr,group,group,ps->ver,ROUTER_ALERT_ON);
	IGMP_TRACE(NULL);
#if 0
	igmp_trace(NULL,htonl(nif->local_addr),htonl(dst),
		   (struct igmp *)(send_buf+IPHDR_LEN+RA_OPT_LEN));
#endif
    }
    if(host->trace_fp) {
	trace(host->trace_fp," join %s\n",inet_atos(htonl(group)));
	if(nif->state == UP)
	    IGMP_TRACE(host->trace_fp);
#if 0
	    igmp_trace(host->trace_fp,htonl(nif->local_addr),htonl(dst),
		   (struct igmp *)(send_buf+IPHDR_LEN+RA_OPT_LEN));
#endif
    }

    /* Add active group list */
    for(grp=active_group;grp!=NULL;grp=grp->next) {
	if(grp->grp_addr == group) break;
    }
    if(!grp) {
	if(IS_DEBUG(DEBUG_TRACE))
	    log(LOG_DEBUG,0," Add New Group %s\n",inet_atos(htonl(group)));

	MALLOC(new_grp, GROUP);
	new_grp->grp_addr = group;
	new_grp->mem_num = 0;
	if(active_group) {
	    for(grp=active_group;grp->next!=NULL;grp=grp->next);
	    grp->next = new_grp;
	    grp = new_grp;
	}
	else 
	    grp = active_group = new_grp;	
    }

    /* Add member each group */
    if(grp->member) {
	if(IS_DEBUG(DEBUG_TRACE))
	    log(LOG_DEBUG,0," Add Join Host %d\n",host->node_id);
	for(mem_list=grp->member;mem_list;mem_list=mem_list->next) {
	    if(mem_list->node == host) break;
	}
	if(mem_list) {
	    if(mem_list->state == LEAVE) {
		mem_list->state = JOIN;
		grp->mem_num++;
	    }
	}
	else {
	    for(mem_list=grp->member;mem_list->next!=NULL;mem_list=mem_list->next);
	    MALLOC(new_mem, MEMBER);
	    new_mem->node = host;
	    new_mem->state = JOIN;
	    mem_list->next = new_mem;
	    grp->mem_num++;
	}
    }
    else {
	if(IS_DEBUG(DEBUG_TRACE))
	    log(LOG_DEBUG,0," New Member %d\n",host->node_id);

	MALLOC(grp->member, MEMBER);
	grp->member->node = host;
	grp->member->state = JOIN;
	grp->mem_num++;
    }

}

/*
 *
 */
void leave_group(id,group)
u_long id;
u_long group;
{
    struct GROUP *grp,*new_grp;
    struct NODE *host;
    struct NODE_IF *nif;
    struct igmp_data *ps;
    struct MEMBER *mem_list,*new_mem;
    u_long dst;

    if(IS_DEBUG(DEBUG_TRACE))
	log(LOG_INFO,0," host leave group %d %s\n",id,inet_atos(htonl(group)));
    /* Host list */
    for(host=host_list;host!=NULL;host=host->next) {
	if(host->node_id == id) break;
    }

    if(!host) {
	printf(" No host \n");
	return;
    }

    nif = &host->ifaddr;
    ps = (struct igmp_data *)nif->if_ps;
    if(ps->group) {
	for(grp=ps->group;grp;grp=grp->next) {
	    if(grp->grp_addr == group) {
		grp->mem_num = 0;
		break;
	    }
	}
    }
    else {
	printf(" No join group \n");
    }

    dst = ALL_ROUTERS_GROUP;
    if(ps->ver == IGMP_VERSION_2 && nif->state == UP) {
	igmp_leave_send(IF_NAME(nif->ifa),nif->local_addr,dst,group,ROUTER_ALERT_ON);
	IGMP_TRACE(NULL);
#if 0
	igmp_trace(NULL,htonl(nif->local_addr),htonl(dst),
		   (struct igmp *)(send_buf+IPHDR_LEN+RA_OPT_LEN));
#endif
    }
    if(host->trace_fp) {
	trace(host->trace_fp," leave %s\n",inet_atos(htonl(group)));
	IGMP_TRACE(host->trace_fp);
#if 0
	igmp_trace(host->trace_fp,htonl(nif->local_addr),htonl(dst),
		   (struct igmp *)(send_buf+IPHDR_LEN+RA_OPT_LEN));
#endif
    }

    for(grp=active_group;grp!=NULL;grp=grp->next) {
	if(grp->grp_addr == group) break;
    }
    if(!grp) {
	printf(" No group %s\n",inet_atos(htonl(group)));
	return ;
    }

    if(grp->member) {
	for(mem_list=grp->member;mem_list!=NULL;mem_list=mem_list->next) {
	    if(mem_list->node == host) break;
	}
	if(!mem_list) {
	    printf(" host %d is non-member\n",host->node_id);
	    return;
	}
	mem_list->state = LEAVE;
	grp->mem_num--;
	if(IS_DEBUG(DEBUG_TRACE))
	    log(LOG_INFO,0," Delete Member %d\n",host->node_id);
    }

}

/*
 *
 */
void join_leave_group(id,group,period,interval)
u_long id,group;
int period,interval;
{
    struct NODE *host;
    struct NODE_IF *nif;
    struct igmp_data *ps;
    struct GROUP *grp;

    if(IS_DEBUG(DEBUG_TRACE))
	log(LOG_INFO,0," join_leave %d, %s, %d, %d\n",
	    id,inet_atos(htonl(group)),period,interval);

    /* Host list */
    NODE_SEARCH(host,id);

    nif = &host->ifaddr;
    ps = (struct igmp_data *)nif->if_ps;
    ps->query_time = interval;
    ps->qtimer = (char *)timer_init(id,ps,join_leave_timeout);
    ps->recv_time = currnt_time + period;

#if 0
    grp = ps->group;
    if(grp && grp->mem_num)
	leave_group(id,grp->grp_addr);
    else
	join_group(id,group);
#endif
    join_group(id,group);
    timer_set(ps->qtimer,ps->query_time);
}

/*
 *
 */
void host_filter_packet(id,type,flag)
u_long id;
int type;
int flag; /* filter or no-filter */
{
    struct NODE *host;
    struct NODE_IF *nif;
    struct FILTER *filtp,*filtp2;

    if(IS_DEBUG(DEBUG_TRACE))
	log(LOG_INFO,0," host_filter_packet %d %d %d\n",id,type,flag);

    /* Host list */
    NODE_SEARCH(host,id);

    if(host->trace_fp)
	trace(host->trace_fp," filter packet %d %d\n",type,flag);

    nif = &host->ifaddr;
    filtp2 = NULL;
    if(flag) {  /* add filter info */
#if 0
	filtp = (struct FILTER *)malloc(sizeof(struct FILTER));
	MALLOC(filtp, FILTER);
#endif
	filtp->type = FILTER_PKT;
	filtp->info = type;
	if(nif->filtp) {
	    for(filtp2=nif->filtp;filtp2->next!=NULL;filtp2=filtp2->next);
	    filtp2->next = filtp;
	}
	else {
	    nif->filtp = filtp;
	}
    }
    else {      /* delete filter info */
	for(filtp=nif->filtp;filtp!=NULL;filtp=filtp->next) {
	    if(filtp->type == FILTER_PKT && filtp->info == type) {
		if(filtp2) 
		    filtp2->next = filtp->next;
		else {
		    if(filtp == nif->filtp && filtp->next)
			nif->filtp = filtp->next;
		}
		free(filtp);
		return ;
	    }
	    filtp2=filtp;
	}
    }
}

/*
 *
 */
void join_leave_timeout(id,data)
u_long id;
char *data;
{
    struct igmp_data *ps;
    struct GROUP *grp;
    struct MEMBER *mem;

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

    ps = (struct igmp_data *)data;
    grp = ps->group;
    if(grp->mem_num)
	leave_group(id,grp->grp_addr);
    else
	join_group(id,grp->grp_addr);
    if(ps->recv_time > currnt_time)
	timer_set(ps->qtimer,ps->query_time);
    else 
	timer_stop(ps->qtimer);
}

/*
 *
 */
void recv_timeout(id,data)
u_long id;
char *data;
{
    timer_stop(recv_timer);
    if(compare) {
	printf("    Timeout Receive Packet(code:%d  group:%s) \n",
	       compare->igmp_code,inet_atos(htonl(compare->igmp_group)));
	log(LOG_INFO,0,"     Timeout Receive Packet(code:%d  group:%s) \n",
	       compare->igmp_code,inet_atos(htonl(compare->igmp_group)));
	free(compare);
	compare = NULL;
    }
}

/*
 *
 */    
void packet_recv(code,group,timeout)
int code;
u_long group;
int timeout;
{
    if(IS_DEBUG(DEBUG_TRACE))
	log(LOG_DEBUG,0," packet recv %d, %s, %d\n", code,inet_atos(htonl(group)),timeout);

    MALLOC(compare, igmp);
    compare->igmp_code = code;
    compare->igmp_group = group;
    if(!recv_timer)
	recv_timer = timer_init(0,NULL,recv_timeout);
    timer_set(recv_timer,timeout);
}

/*
 *
 */
void host_state(id,flag)
u_long id;
int flag;
{
    struct NODE *host;
    struct NODE_IF *nif;
    struct igmp_data *ps;
    char *state[] = {"Down","Up"};

    if(IS_DEBUG(DEBUG_TRACE))
	log(LOG_INFO,0," host state id %d %s\n",id,state[flag]);

    /* Host list */
    NODE_SEARCH(host,id);

    nif = &host->ifaddr;
    nif->state = flag;

    if(host->trace_fp) {
	trace(host->trace_fp," %s\n",state[flag]);
    }

}

/*
 *
 */
int filter_check(src,dst,type,filtp)
u_long src,dst;
char type;
struct FILTER *filtp;
{
    struct FILTER *fp;

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

    for(fp=filtp;fp!=NULL;fp=fp->next) {
	if(fp->type == FILTER_PKT) {
	    if(IS_DEBUG(DEBUG_TRACE)) log(LOG_INFO,0," %x \n",fp->info);
	    if(type == IGMP_MEMBERSHIP_QUERY) {
		if(fp->info == FILTER_QUERY)
		    return 1;
	    }
	    
	}
	else if(fp->type == FILTER_SRC) {
	    if(fp->info == src) return 1;
	}
	else if(fp->type == FILTER_DST) {
	    if(fp->info == dst) return 1;
	}
    }

    return 0;
}

/*
 *
 */
void join_host_report(src,query_grp,igmp)
u_long src;
u_long query_grp;
struct igmp *igmp;
{
    char *if_name;
    struct NODE *host;
    struct NODE_IF *nif;
    struct if_info *ifi,*bind_interface();
    struct ip *ip;
    int rtn;
    short ver;
    u_long dst;
    struct igmp_data *ps;
    struct GROUP *grp;
    struct MEMBER *mem;

    igmp_trace(NULL,htonl(src),htonl(query_grp),igmp);

    if(compare) {
	/* we are packet recv mode */
	/*printf(" Checking Receive Packet -->");*/
	if(igmp->igmp_code == compare->igmp_code
	&& ntohl(igmp->igmp_group) == compare->igmp_group) {
	    printf(" Receive Packet code:%d  group:%s\n",
	       compare->igmp_code,inet_atos(compare->igmp_group));
	    wait_timeout(0,NULL);
	/*    printf(" OK \n");*/
	    log(LOG_INFO,0,"     Receive Packet --> code:%d, group:%s (Match) \n",igmp->igmp_code,inet_atos(igmp->igmp_group));
	    free(compare);
	    compare = NULL;
	}
	else {
	    /* printf(" NG : %d, %x \n",igmp->igmp_code,igmp->igmp_group);*/
	    log(LOG_INFO,0,"     Receive Packet --> code:%d, group:%s (Mismatch) \n",igmp->igmp_code,inet_atos(htonl(igmp->igmp_group)));
	}
/*	return;*/
    }
	
    for(host=host_list;host!=NULL;host=host->next) {
	if(host->trace_fp) {
	    nif=(struct NODE_IF *)&host->ifaddr;
	    if(!nif || ((IF_NETMASK(nif->ifa) & IF_ADDR(nif->ifa)) ==
			(IF_NETMASK(nif->ifa) & src))) {
		igmp_trace(host->trace_fp,htonl(src),htonl(query_grp),igmp);
	    }
	}
    }

/*		   (struct igmp *)(recv_buf+IPHDR_LEN));*/

    if(!active_group)
	return ;
    
/*    if(query_grp != ALL_HOSTS_GROUP)
	return;
*/
    for(grp=active_group;grp!=NULL;grp=grp->next) {
	if(query_grp != ALL_HOSTS_GROUP 
	&& grp->grp_addr != query_grp)
	    continue;

	if(grp->member) {
	    for(mem=grp->member;mem;mem=mem->next) {
		if(mem->state == JOIN) {
		    host=mem->node;
		    nif=(struct NODE_IF *)&host->ifaddr;
		    if(nif && nif->state == UP) {
			if((IF_NETMASK(nif->ifa) & IF_ADDR(nif->ifa)) ==
			   (IF_NETMASK(nif->ifa) & src)) {
			    break;
			}
		    }
		}
	    }
	    if(!mem)  /* All Member Leaved */ 
		continue;
	}
	else {
	    continue;
	}

	if(nif->filtp) {
	    log(LOG_INFO,0," %d \n",host->node_id);
	    if(filter_check(src,query_grp,igmp->igmp_type,nif->filtp))
		continue;
	}

	ps = (struct igmp_data *)nif->if_ps;
	if_name = IF_NAME(nif->ifa);

#if 0
    ip = (struct ip *)send_buf;
    igmp = (struct igmp *)(ip+1);

    if(ver == IGMP_VERSION_1) igmp->igmp_type = IGMP_MEMBERSHIP_REPORT;
    else if(ver == IGMP_VERSION_2) igmp->igmp_type = IGMP_V2_MEMBERSHIP_REPORT;

    igmp->igmp_type = IGMP_V2_MEMBERSHIP_REPORT;
    igmp->igmp_code = 0;
    igmp->igmp_group = htonl(active_group);
    igmp->igmp_cksum = 0;
    igmp->igmp_cksum = in_cksum((u_short *)igmp, sizeof(struct igmp));
    dst = grp->grp_addr;
    src = ifaddr = nif->local_addr;

    rtn = igmp_send(htonl(ifaddr),htonl(src),ip,htonl(dst),sizeof(struct ip)+sizeof(struct igmp),IGMP_TTL);
#endif

/*
	if((IF_NETMASK(nif->ifa) & IF_ADDR(nif->ifa)) == (IF_NETMASK(nif->ifa) & src)) {
*/
	igmp_report_send(IF_NAME(nif->ifa),nif->local_addr,grp->grp_addr,grp->grp_addr,ps->ver,ROUTER_ALERT_ON);
	dst = grp->grp_addr;
	IGMP_TRACE(NULL);
#if 0
	igmp_trace(NULL,htonl(nif->local_addr),htonl(grp->grp_addr),
		   (struct igmp *)(send_buf+IPHDR_LEN+RA_OPT_LEN));
#endif
	if(host->trace_fp) {
	    IGMP_TRACE(host->trace_fp);
#if 0
	    igmp_trace(host->trace_fp,htonl(nif->local_addr),
		       htonl(grp->grp_addr),
		       (struct igmp *)(send_buf+IPHDR_LEN+RA_OPT_LEN));
#endif
	}
/*	}
*/
    }
}

/*
 *
 */
void host_trace(id,file)
u_long id;
char *file;
{
    struct NODE *host;

    for(host=host_list;host!=NULL;host=host->next) {
	if(host->node_id == id) break;
    }
    if(!host) {
	printf(" No host \n");
	return;
    }

    if((host->trace_fp=fopen(file,"w+")) == NULL) {
	printf(" %s can't open \n",file);
    }

    trace(host->trace_fp,"\n %s\n",version);
    /*    trace(host->trace_fp," %s\n\n",copyright);*/

}
    
/*
 *
 */
void host_dump(id,file)
u_long id;
char *file;
{
    struct NODE *host;
    struct NODE_IF *nif;
    struct GROUP *grp;
    struct igmp_data *ps;
    FILE *fp;
    char *state[] = {"Down","Up"};
    struct FILTER *filtp;
    char *ftype[] = {" ","packet","src","dst"};

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

    NODE_SEARCH(host,id);
    trace(fp," Host %d \n",host->node_id);
    nif = &host->ifaddr;
/*    trace(fp," \t Addr: %s(%s) ", 
	       inet_atos(htonl(IF_ADDR(nif->ifa))),IF_NAME(nif->ifa));
*/
    trace(fp," \t Local addr: %s(%s) ", 
	       inet_atos(htonl(nif->local_addr)),IF_NAME(nif->ifa));
    ps = (struct igmp_data *)nif->if_ps;
    trace(fp,"  Ver: %d   state: %s\n",ps->ver,state[nif->state]);
    trace(fp," \t Group: ");
    for(grp=ps->group;grp;grp=grp->next) {
	if(grp->mem_num) 
	    trace(fp," %s",inet_atos(htonl(grp->grp_addr)));
	else 
	    trace(fp," (%s)",inet_atos(htonl(grp->grp_addr)));
    }
    trace(fp,"\n");
#if 0
    trace(fp," \t Filter: \n");
    for(filtp=nif->filtp;filtp!=NULL;filtp=filtp->next) {
	trace(fp,"\t   %s %d \n",ftype[filtp->type],filtp->info);
    }
#endif
    if(host->trace_fp && file) {
	trace(host->trace_fp," dump %s\n",file);
    }
}

/*
 *
 */
void dump()
{
    struct NODE *host;
    struct NODE_IF *nif;
    struct GROUP *grp;
    struct MEMBER *mem_list;
    struct igmp_data *ps;
    char *state[] = {" ","Join","Leave"};

    for(host=host_list;host!=NULL;host=host->next) {
	host_dump(host->node_id,NULL);
    }

    printf("\n");
    for(grp=active_group;grp!=NULL;grp=grp=grp->next) {
	printf(" Group: %s member %d\n",
	       inet_atos(htonl(grp->grp_addr)),grp->mem_num);
	for(mem_list=grp->member;mem_list!=NULL;mem_list=mem_list->next) {
	    printf(" \t %d %s\n",mem_list->node->node_id,state[mem_list->state]);
	}
    }
}
