/************************************************************************/
/*	Routing Protocol Simulator	Release 1.0	1994/3/17	*/
/*                                              1.21    1997/2/10       */
/*									*/
/*		module 	: protocol procedure	      			*/
/*		file	: ospf_pkt.c			       		*/
/*									*/
/*   Copyright (c) 1994-1997 by Systems Development Laboratory Hitachi, */
/*   Ltd. All rights reserved.						*/
/*----------------------------------------------------------------------*/
/*	UPDATE HISTORY							*/
/*									*/
/************************************************************************/
static char copyright[]=
  "@(#)Copyright (c) 1994-1997 by Systems Development Laboratory Hitachi,Ltd.\n All rights researved.\n";

#include "rps.h"
#include "rps_ospf.h"
#include "ospf_type.h"
#include "netmng.h"
#include "router.h"
/*
#define  DEBUG 1
*/
extern struct NET_TBL *get_link_net();
extern struct RT_TBL *rt_search();
extern u_long get_dr_addr();
extern u_long get_bdr_addr();
extern u_long get_dr_id();
extern u_long get_bdr_ida();
extern FILE *get_trace_fp();
extern byte *get_rt_table();
extern byte *search_lsdb();
extern byte *search_lsdb_sum();
extern byte *search_lsdb_sum_list();
extern byte *get_lsdb_sum_entry();
extern byte *make_lsdb_sum_list();
extern struct NET_TBL *get_link_net();
extern void ospf_rxpkt();
extern void hello_time_out();
extern void retrans_time_out();
extern byte *timer_init();
extern char *time_to_char();
extern struct NET_TBL *get_net_with_ifaddr();
extern struct in_addr *if_inetaddr();
extern char *mem_alloc();
extern struct RT_IFCONF *get_local_rtif();
void bin_dump();

void ospf_send();
void ospf_hello_dump();
void ospf_db_dump();
void ospf_req_dump();
void ospf_update_dump();
void ospf_ack_dump();
void ospf_packet_dump();
void ospf_hdr_dump();

#define MAX_SIZE	1200
/*
#ifdef SDL_VXWORKS

#define		IP_OPTIONS	1
#define		IP_MULTICAST_IF	2
#define		IP_MULTICAST_TTL 3
#define		IP_MULTICAST_LOOP 4
#define		IP_ADD_MEMBERSHIP 5
#define		IP_DROP_MEMBERSHIP 6

struct ip_mreq {
    struct in_addr imr_multiaddr;
    struct in_addr imr_interface;
};


#endif
*/
static byte ospf_send_buff[MAX_SIZE];
static byte ospf_hello_buff[MAX_SIZE/4];

#define OSPF_SEND_ALLOC(ptr,type,size) \
  { \
      bzero(ospf_send_buff,MAX_SIZE); \
      ptr = (struct type *)ospf_send_buff; \
   }

#define OSPF_HELLO_ALLOC(ptr,type,size) \
  {  \
     bzero(ospf_hello_buff,MAX_SIZE/4); \
     ptr = (struct type *)ospf_hello_buff; \
  }

int send_packet_length;
int recv_packet_length;

#define	INET_ADDR_ALLROUTERS	0xe0000002

int ospf_sock = -1;
int inet_sock = -1;

char *pkt_type[] = {"none","HELLO","DATABASE","REQUEST","UPDATE","ACK"};
char *auth_type[] = {"None","Simple"};

int ospf_send_packet_num = 0;
int ospf_recv_packet_num = 0;

byte *hello_buf;

#ifdef BSD
#define IP_ADD_MEMBERSHIP    12
#endif BSD
/*

  ospf_init

*/
int ospf_init(id,proto_info)
u_long id;
byte *proto_info;
{
    struct PROTO_OSPF *ospf;
    int type;
    struct OSPF_IF *intf;
    struct OSPF_NBR *nbr;
    struct OSPF_AREA *area;
    struct RT_TBL *rt,*cnct;
    struct NET_TBL *net;
    struct INDEX *index,*cindex;
    u_long dst,gw;
    struct in_addr addr;
    u_char ttl,loop;
#ifdef MULTICAST
    struct ip_mreq mreq;
#endif

    ospf = (struct PROTO_OSPF *)proto_info;
    for(area=ospf->myarea;area;area=area->next) {
	intf = area->intf;
	nbr = intf->nbr;
	nbr->sum_list = NULL;
	nbr->recv_time = get_currnt_time();
	  
	rt = rt_search(id);

	nbr->nbr_id = get_rtid_with_ifaddr(IF_ADDR(nbr->nbr_addr));

	net = get_net_with_ifaddr(id,IF_ADDR(intf->ifaddr));
	MALLOC(intf->ifaddr->net,in_addr);
	IF_NET(intf->ifaddr) = net->addr;
	MALLOC(intf->ifaddr->net_mask,in_addr);
	IF_NETMASK(intf->ifaddr) = net->mask;
    
	intf->htimer=timer_init(id,intf,hello_time_out);
	intf->rtimer=NULL;
	/*	intf->rtimer=timer_init(id,intf,retrans_time_out);*/
    }

    if(ospf_sock < 0) {
	ospf_sock = get_socket(SOCK_RAW,IPPROTO_OSPF,ospf_rxpkt);
	ospf_send_packet_num = 0;
	ospf_recv_packet_num = 0;

	if(intf->type == BROADCAST) {
	    
#ifdef MULTICAST
       	dst = OSPF_ALLSPF_ADDR;
	gw = LOCAL_LOOPBACK_ADDR;
	sys_route_add(dst,gw);
#endif
	
        }
    }

    if(intf->type == BROADCAST) {
	
#ifdef MULTICAST
		
	loop = 0;
	if(setsockopt(ospf_sock,IPPROTO_IP,IP_MULTICAST_LOOP,(char *)&loop,sizeof(loop))) {
	    perror("setsockopt(IP_MULTICAST_LOOP)");
	    return ;
	}


/*	ttl = 1;
	if(setsockopt(ospf_sock,IPPROTO_IP,IP_MULTICAST_TTL,(char *)&ttl,sizeof(ttl))) {
	    perror("setsockopt");
	    return ;
	}
*/

	mreq.imr_multiaddr.s_addr = htonl(OSPF_ALLSPF_ADDR);
	mreq.imr_interface.s_addr = htonl(IF_ADDR(intf->ifaddr));
	if(setsockopt(ospf_sock,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char *)&mreq,sizeof(mreq))) {
	    perror("setsockopt(IP_ADD_MEMBERSHIP) : OSPF_ALLSPF_ADDR");
	    return ;
	}

	if(intf->priority) {
	    mreq.imr_multiaddr.s_addr = htonl(OSPF_ALLDR_ADDR);
	    mreq.imr_interface.s_addr = htonl(IF_ADDR(intf->ifaddr));
	    if(setsockopt(ospf_sock,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char *)&mreq,sizeof(mreq))) {
		perror("setsockopt(IP_ADD_MEMBERSHIP) : OSPF_ALLDR_ADDR");
		return ;
	    }
	}
	
	addr.s_addr = htonl(IF_ADDR(intf->ifaddr));
	if(setsockopt(ospf_sock,IPPROTO_IP,IP_MULTICAST_IF,(char *)&addr,sizeof(addr))) {
	    perror("setsockopt(IP_MULTICAST_IF)");
	    return ;
	}

	if(inet_sock < 0) {
	    inet_sock = get_socket(SOCK_DGRAM,0 ,NULL);
	}

       	mreq.imr_multiaddr.s_addr = htonl(INET_ADDR_ALLROUTERS) ;
	mreq.imr_interface.s_addr = htonl(IF_ADDR(intf->ifaddr));
	if(setsockopt(inet_sock,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char *)&mreq,sizeof(mreq))) {
	    perror("setsockopt(IP_ADD_MEMBERSHIP) : INET_ADDR_ALLROUTERS");
	    return ;
	}
	
#else
	log_trace(stderr,"\n Configuration is multicast interface");
	log_trace(stderr,"\n But this module don't support multicast\n\n");
	if(ospf_sock > 0) {
	    ospf_sock = -1;
	}
	exit(1) ;

#endif

    }

    lsdb_init();
}

/*

  ospf_term

*/
int ospf_term(id,proto_info)
u_long id;
byte *proto_info;
{
    struct PROTO_OSPF *ospf;
    int type;
    struct OSPF_IF *intf;
    struct OSPF_NBR *nbr;
    u_long dst,gw;
    
    ospf = (struct PROTO_OSPF *)proto_info;
    intf = ospf->myarea->intf;
    nbr = intf->nbr;
    nbr->sum_list = NULL;

    if(ospf_sock > 0) {
	ospf_sock = -1;

	if(intf->type == BROADCAST) {
	
#ifdef MULTICAST
	    dst = OSPF_ALLSPF_ADDR;
	    gw = LOCAL_LOOPBACK_ADDR;
	    sys_route_delete(dst,gw);
#endif
	}
    }


#ifdef VXWORKS    
    fprintf(stderr," \n ospf_send_packet_num = %d\n",ospf_send_packet_num);
    fprintf(stderr," ospf_recv_packet_num = %d\n",ospf_recv_packet_num);
#endif
    
}

/*

  set_dr

*/
void set_dr(id,nbr,intf)
u_long id;
struct OSPF_NBR *nbr;
struct OSPF_IF *intf;
{
    u_long net_addr;
    u_long dr,bdr;
    u_long my_addr;
    
    net_addr = IF_NET(intf->ifaddr);
    my_addr = IF_ADDR(intf->ifaddr);

    dr = bdr = 0;
    if(intf->priority) {
	dr = get_dr_addr(net_addr);
	if(dr == my_addr) {
/*	    bdr = get_bdr_addr(net->addr);*/
	}
	else {
	    dr = my_addr;
/*	    bdr = get_dr_addr(net->addr);*/
	    change_dr(net_addr,id,nbr->nbr_id);
	    table_update(id,IF_ADDR(intf->ifaddr));
	}
    }
    else {
/*	dr = get_dr_addr(net_addr);*/
/*	bdr = get_bdr_addr(net->addr);*/
    }

    intf->dr = dr;
/*    intf->bdr = bdr;*/

    nbr->dr = dr;
/*    nbr->bdr = bdr;*/
}
    

    
/*

  ospf_send_hello

*/
int ospf_send_hello(id,nbr,intf)
u_long id;
struct OSPF_NBR *nbr;
struct OSPF_IF *intf;
{
    int lock = int_lock();
    struct HELLO_PKT *hello;
    u_short pkt_len;
    u_long *nbr_list;
    int nbr_num;
    u_long dst;

/*    nbr_num = get_nbr_num(id,IF_ADDR(intf->ifaddr));*/
    pkt_len = OSPF_HDR_SIZE + HELLO_PACKET_SIZE ; 
    OSPF_HELLO_ALLOC(hello,HELLO_PKT,pkt_len);

    nbr_num = 0;
    hello->hdr.type = OSPF_HELLO_PKT;
    
    hello->netmask = htonl(IF_NETMASK(intf->ifaddr));
    hello->hello_int = htons(intf->hello_timer);
    hello->dead_int = htonl(intf->dead_timer);
    hello->priority = intf->priority;
    if(intf->area->type == AREA_TYPE_STUB) {
	hello->options = (byte)0;
    }
    else {
	hello->options = E_OPTION;
    }

    if(intf->dr != 0) {
	hello->dr = htonl(intf->dr);
    }
    if(intf->bdr != 0) {
	hello->bdr = htonl(intf->bdr);
    }

    nbr_list = &(hello->nbr);
    if(intf->type > NONBROADCAST) {
	if(nbr->state > NBR_ATTEMPT) {
	    *nbr_list = htonl(nbr->nbr_id);
	    nbr_num = 1;
	}
    }
    else {
	if(nbr->state > NBR_ATTEMPT)
	  nbr_num = (u_short)get_nbr_list(id,IF_ADDR(intf->ifaddr),nbr_list);
	else
	  nbr_num = 0;
    }

    pkt_len += nbr_num * 4;

    ospf_send_packet(id,(byte *)hello,pkt_len,intf);

    int_unlock(lock);
    
    return 1;
}


/*

  ospf_send_database

*/
int ospf_send_database(id,nbr,intf)
u_long id;
struct OSPF_NBR *nbr;
struct OSPF_IF *intf;
{
    int lock = int_lock();
    struct DB_PKT *db,*dbp;
    struct DB_SUM *dbsum;
    long len;
    struct OSPF_AREA *area;
    short dbnum;
        
    area = intf->area;
    if(nbr->sum_list == NULL || (nbr->bits & INIT)) {
	MALLOC(dbsum,DB_SUM);
	OSPF_SEND_ALLOC(dbsum->db,DB_PKT,OSPF_HDR_SIZE + DB_PACKET_SIZE);
	dbsum->len = OSPF_HDR_SIZE + DB_PACKET_SIZE;
	nbr->sum_list = dbsum;
	db = dbsum->db;
    }
    else {
	dbsum = nbr->sum_list;
	len = dbsum->len;
	OSPF_SEND_ALLOC(db,DB_PKT,len);

	dbnum = (short)get_lsdb_sum_list(id,dbsum->rt_table,&(db->db),nbr->nbr_id);
	if(dbsum->db_num && dbsum->db_num != dbnum)
	  dbsum->len = OSPF_HDR_SIZE + DB_PACKET_SIZE + LS_HDR_SIZE * dbnum;
    }

    db->hdr.type = OSPF_DB_PKT;
    
    len = dbsum->len;
    db->reserve = 0;
    if(lsdb_sum_more(dbsum->rt_table))
      db->db_bit = MORE;
    db->db_bit |= nbr->bits;
    db->seq = htonl(nbr->seq);
    if(intf->area->type == AREA_TYPE_STUB) {
	db->options = (byte)0;
    }
    else {
	db->options = E_OPTION;
    }

    ospf_send_packet(id,db,len,intf);
    
    int_unlock(lock);

    return 1;
}

/*

  ospf_send_req

*/
int ospf_send_req(id,nbr,intf)
u_long id;
struct OSPF_NBR *nbr;
struct OSPF_IF *intf;
{
    struct LS_REQ *lsreq;
    struct LS_REQ_PKT *req;
    short len;
    byte *reqp;
    
    if(nbr->req_list == NULL) return ;
    
    OSPF_SEND_ALLOC(req,LS_REQ_PKT,OSPF_HDR_SIZE + LS_REQ_PACKET_SIZE);

    req->hdr.type = OSPF_LS_REQ_PKT;
    
    len = OSPF_HDR_SIZE;
    reqp = (byte *)&(req->reserve1);
    for(lsreq=nbr->req_list;lsreq;lsreq=lsreq->next) {
	bzero(reqp,sizeof(short));
	reqp+=sizeof(short);
	bzero(reqp,sizeof(byte));
	reqp++;
	*reqp = lsreq->ls_type;
	reqp++;
     	bcopy((byte *)&(lsreq->ls_id),reqp,sizeof(long));
	reqp+=sizeof(long);
	bcopy(&(lsreq->adv_rt),reqp,sizeof(long));
	reqp+=sizeof(long);
	if(len + LS_REQ_PACKET_SIZE > INTF_MTU)
	  break;
	else
	  len += LS_REQ_PACKET_SIZE;
    }
    
    ospf_send_packet(id,req,len,intf);

    return 1;
}

/*

  ospf_send_update

*/
int ospf_send_update(id,nbr,intf,rt_table)
u_long id;
struct OSPF_NBR *nbr;
struct OSPF_IF *intf;
byte *rt_table;
{

    int lock = int_lock();
    struct LS_UPDATE_PKT *update;
    int adv_num,adv_len;
    byte *adv,*adv_ptr;
    int len,update_len;
    struct OSPF_AREA *area;
    int flag;
    byte *lsdb_sum,*lsdb;
    byte ls_type;

    area = intf->area;
    
    update_len = OSPF_HDR_SIZE + LS_UPDATE_PACKET_SIZE ;
    OSPF_SEND_ALLOC(update,LS_UPDATE_PKT,len);

    update->hdr.type = OSPF_LS_UPDATE_PKT;
    
    adv = adv_ptr = (byte *)&update->adv;
    adv_num = 0;
    
    if(area->type == AREA_TYPE_STUB)
      flag = 0;
    else
      flag = 1;

    lsdb_sum = NULL;
    
    for(lsdb_sum=get_lsdb_sum_entry(id,rt_table,NULL);lsdb_sum;lsdb_sum=get_lsdb_sum_entry(id,rt_table,lsdb_sum)) {
/*	if((lsdb = search_lsdb_sum(area->id,id,lsdb_sum)) == NULL) {
	    break;
	}
*/
	if(LSDB_ENTRY_CHANGE(lsdb_sum) == LSDB_NOCHANGE)
	  continue;
	
	len = LSDB_ENTRY_LEN(lsdb_sum);
	ls_type = LSDB_ENTRY_TYPE(lsdb_sum);

	if(update_len + len >= INTF_MTU) {
	   update->hdr.type = OSPF_LS_UPDATE_PKT;
	   update->adv_num = htonl(adv_num);
	   ospf_send_packet(id,update,update_len,intf);
	   update_len = OSPF_HDR_SIZE + LS_UPDATE_PACKET_SIZE;
	   OSPF_SEND_ALLOC(update,LS_UPDATE_PKT,update_len);
	   adv = adv_ptr = (byte *)&update->adv;
	   adv_num = 0;
       }

	len = get_lsdb_entry(ls_type,(struct LSDB_SUM_LIST *)lsdb_sum,&adv,intf->trans_timer);
	if (!len) continue;
	adv_num++;
	(byte *)adv += len;
	update_len += len;
    }

    update->hdr.type = OSPF_LS_UPDATE_PKT;
    update->adv_num = htonl(adv_num);

    ospf_send_packet(id,update,update_len,intf);

    int_unlock(lock);
    return 1;
}

/*

  ospf_send_ack

*/
int ospf_send_ack(id,nbr,intf)
u_long id;
struct OSPF_NBR *nbr;
struct OSPF_IF *intf;
{
    struct LS_ACK_PKT *ack;
    struct DB_SUM *dbsum;
    struct DB_PKT *dbp;
    struct LS_HDR *lsh,*hdr;
    long len,sum_len;
    short pkt_len;
    byte *lsdb;
    int num;
    
    if(nbr->sum_list == NULL) {
	lsdb = intf->area->lsdb;
	make_lsdb_sum_list(id,lsdb,nbr->nbr_id);

	num = nbr_lsdb_entry_num(id,lsdb);
	
	MALLOC(dbsum,DB_SUM);
	
	len = OSPF_HDR_SIZE + DB_PACKET_SIZE + num * LS_HDR_SIZE;
	
	OSPF_MALLOC(dbp,DB_PKT,len);
	dbsum->len = len;
	dbsum->db_num = (short)get_lsdb_nbr_sum_list(nbr->nbr_id,lsdb,&(dbp->db),id);
    }
    else {
	dbsum = nbr->sum_list;
	len = dbsum->len;
	OSPF_MALLOC(dbp,DB_PKT,len);
	dbsum->db_num = (short)get_lsdb_nbr_sum_list(nbr->nbr_id,dbsum->rt_table,&(dbp->db),id);
    }

    len = OSPF_HDR_SIZE + LS_ACK_PACKET_SIZE;
    OSPF_SEND_ALLOC(ack,LS_ACK_PKT,len);

    ack->hdr.type = OSPF_LS_ACK_PKT;
    
    lsh = &(ack->lsh);
    sum_len = dbsum->len;
    hdr = &(dbp->db);
    pkt_len = OSPF_HDR_SIZE;
    for(len=0;len<sum_len;len+=LS_HDR_SIZE) {
	if(hdr->adv_rt != nbr->nbr_id) {
	    hdr++;
	    continue;
	}
	bcopy(hdr,lsh,LS_HDR_SIZE);
	lsh++;
	hdr++;
	pkt_len+=LS_HDR_SIZE;
    }

    ospf_send_packet(id,ack,pkt_len,intf);    

    free((char *)dbp);
    return 1;
}

/*

  ospf_send_packet

*/
int ospf_send_packet(id,pkt,pkt_len,intf)
u_long id;
byte *pkt;
u_short pkt_len;
struct OSPF_IF *intf;
{
    int lock = int_lock();
    struct OSPF_AREA *area;
    struct OSPF_HDR *hdr;
    struct OSPF_NBR *nbr;
    u_long dst;
    struct in_addr addr;
    u_char ttl,loop;
#ifdef MULTICAST 
    struct ip_mreq mreq;
#endif
    
    area = intf->area;
    nbr = intf->nbr;
    
    hdr = (struct OSPF_HDR *)pkt;
    
    hdr->ver = 2;
    hdr->length = htons(pkt_len);
    hdr->rt_id = htonl(id);
    hdr->area_id = htonl(area->id);
    hdr->authtype = htons(area->authtype);
    hdr->chcksum = 0;
    hdr->auth[0] = 0;
    hdr->auth[1] = 0;
    
    hdr->chcksum = in_cksum((u_short *)pkt,pkt_len);

    hdr->auth[0] = intf->authkey[0];
    hdr->auth[1] = intf->authkey[1];


    switch(intf->type) {
#ifdef MULTICAST
    case BROADCAST : if(hdr->type == OSPF_HELLO_PKT) {
			dst = OSPF_ALLSPF_ADDR;
			addr.s_addr = htonl(IF_ADDR(intf->ifaddr));
	if(setsockopt(ospf_sock,IPPROTO_IP,IP_MULTICAST_IF,(char *)&addr,sizeof(addr))) {
	    perror("setsockopt(IP_MULTICAST_IF)");
	    return ;
	}
		    }
	else {
	    dst = IF_ADDR(nbr->nbr_addr);
	}
	break;
#endif
    case POINT_TO_POINT :
    case VIRTUAL_LINK :
    case NONBROADCAST : dst = IF_ADDR(nbr->nbr_addr);
			break;
    default : return 0;
    }

    ospf_send_packet_num ++;
    if(get_trace_flag(id)) 
      ospf_packet_dump(id,pkt,pkt_len,IF_ADDR(intf->ifaddr),dst,"SEND");

    ospf_txpkt(ospf_sock,pkt,pkt_len,htonl(dst));

    int_unlock(lock);
    return 1;
}
    
/*

  ospf_recv_packet

*/
int ospf_recv_packet(id,ospf,src,dst,pkt)
u_long id;
struct PROTO_OSPF *ospf;
u_long src;
u_long dst;
byte *pkt;
{
    int lock = int_lock();
    struct OSPF_HDR *o_hdr;
    struct OSPF_IF *intf;
    struct OSPF_AREA *area;
    int recv_type;
    struct OSPF_NBR *nbr;
        
    o_hdr = (struct OSPF_HDR *)pkt;
    
    ospf_recv_packet_num ++;

    if(id == 0 || get_trace_flag(id))
      ospf_packet_dump(id,pkt,ntohs(o_hdr->length),src,dst,"RECV");

    if(ospf==NULL) return;
    
    for(area=ospf->myarea;area;area=area->next)
	if(area->id == ntohl(o_hdr->area_id)) break;

    if(area == NULL) return;
    
    intf=area->intf;
/*    if(o_hdr->area_id != intf->area_id) {
	log_trace(stderr,"Area ID Mismatch\n");
	return;
    }
  */  
    switch(o_hdr->type) {
    case OSPF_HELLO_PKT : ospf_recv_hello(id,(struct HELLO_PKT *)pkt,intf,src,dst);
	recv_type = OSPF_HELLO_PKT;
	break;
    case OSPF_DB_PKT : ospf_recv_db(id,(struct DB_PKT *)pkt,intf,src,dst);
	recv_type = OSPF_DB_PKT;
	break;
    case OSPF_LS_REQ_PKT : ospf_recv_req(id,(struct LS_REQ_PKT *)pkt,intf,src,dst);
	recv_type = OSPF_LS_REQ_PKT;
	break;
    case OSPF_LS_UPDATE_PKT : ospf_recv_update(id,(struct LS_UPDATE_PKT *)pkt,intf,src,dst);
	recv_type = OSPF_LS_UPDATE_PKT;
	break;
    case OSPF_LS_ACK_PKT : ospf_recv_ack(id,(struct LS_ACK_PKT *)pkt,intf,src,dst);
	recv_type = OSPF_LS_ACK_PKT;
	break;
	default : break;
    }

    nbr = intf->nbr;
    nbr->recv_time = get_currnt_time();

    int_unlock(lock);
    
    return recv_type;
}

/*

  dbsum_list

*/
int dbsum_list(id,nbr,intf)
u_long id;
struct OSPF_NBR *nbr;
struct OSPF_IF *intf;
{
    struct DB_PKT *dbp;
    struct DB_SUM *dbsum;
    u_short len;
    byte *lsdb;
    short num;
    
    lsdb = intf->area->lsdb;
    intf->area->adv_lsa=make_lsdb_sum_list(id,lsdb,nbr->nbr_id);

    num = my_lsdb_entry_num(id,lsdb);
    
    MALLOC(dbsum,DB_SUM);
    len = DB_PACKET_SIZE + num * LS_HDR_SIZE ;
    OSPF_MALLOC(dbsum->db,DB_PKT,len);

    dbp = dbsum->db;
    dbsum->db_num = num;
    /*    dbsum->rt_table = lsdb;*/
    dbsum->rt_table = intf->area->adv_lsa;
    nbr->sum_list = dbsum;
    
    len += OSPF_HDR_SIZE ;
    
    if(len != OSPF_HDR_SIZE + DB_PACKET_SIZE) {
	if(nbr->mode == SLAVE)
	  dbsum->db->db_bit = 0;
	dbsum->len = len;
    }

}

/*

  lsreq_list

*/
int lsreq_list(my_id,dbp,nbr,intf,len)
u_long my_id;
struct DB_PKT *dbp;
struct OSPF_NBR *nbr;
struct OSPF_IF *intf;
u_short len;
{
    struct LS_HDR *lsh,*buf;
    struct LS_REQ *req,*list;
    short num;
    byte *rt_table;

    buf = NULL;
    if(nbr->req_list) {
	for(list=nbr->req_list;list->next;list=list->next);
    }
    else {
	list = NULL;
    }
    
    if(dbp == NULL) {
	rt_table = intf->area->lsdb;
	num = nbr_lsdb_entry_num(my_id,rt_table);
	len = num * LS_HDR_SIZE;
	
	OSPF_MALLOC(buf,LS_HDR,len);

	num = (short)get_lsdb_nbr_sum_list(nbr->nbr_id,rt_table,buf,my_id);
	lsh = buf;
    }
    else {
	lsh = &(dbp->db);
    }

    for(;len ; len -= LS_HDR_SIZE,lsh++) {
	switch(lsh->ls_type) {
	case LS_TYPE_RT:
	case LS_TYPE_NET:
	case LS_TYPE_SUM_NET:
	case LS_TYPE_SUM_ASBR:
	case LS_TYPE_ASE: break;
	default :return 0;
	}

	if(ntohl(lsh->adv_rt) == my_id)
	  continue;
	
	MALLOC(req,LS_REQ);
	req->ls_type = lsh->ls_type;
	req->ls_id = lsh->ls_id;
	req->adv_rt = lsh->adv_rt;
	req->ls_seq = lsh->ls_seq;
	req->ls_chksum = lsh->ls_chksum;
	if(nbr->req_list == NULL) {
	    nbr->req_list = list = req;
	}
	else {
	    list->next = req;
	    list = req;
	}
    }
    
    if(buf)  free((char *)buf);
    return 1;
}
	
	    
	    
/*

  ospf_recv_hello

*/
int ospf_recv_hello(id,hello,intf,src,dst)
u_long id;
struct HELLO_PKT *hello;
struct OSPF_IF *intf;
u_long src;
u_long dst;
{
    struct OSPF_NBR *nbr;
    u_long *nbr_list;
    int nbr_num;
    int nbr_is_dr,nbr_is_bdr;
    int backup_seen, nbr_change;
    int my_id_include;
    
    if(intf->state == IFS_DOWN) {
	if(intf->type == VIRTUAL_LINK) return 0;
	ospf_if_state_ifup(id,intf);
	return 0;
    }

    if(ntohs(hello->hello_int) != intf->hello_timer) {
	log_trace(stderr,"Hello Timer Mismatch\n");
	return 0;
    }

    if(ntohl(hello->dead_int) != intf->dead_timer) {
	log_trace(stderr,"RouterDead Timer Mismatch\n");
	return 0;
    }

    if(ntohl(hello->netmask) != IF_NETMASK(intf->ifaddr)) {
	log_trace(stderr,"Netmask Mismatch\n");
	return 0;
    }

    nbr = intf->nbr;
    nbr_is_dr = nbr_is_bdr = FALSE;
    backup_seen = nbr_change = FALSE;
    my_id_include = FALSE;
    
    if(IF_ADDR(nbr->nbr_addr) != src) {
	return 0;
    }

    if(intf->type == NONBROADCAST || intf->type == VIRTUAL_LINK) {
	if((nbr->state == NBR_ATTEMPT) || (nbr->state == NBR_DOWN))
	  ospf_nbr_state_hello(id,intf,nbr);
    }
    else if(nbr->state == NBR_DOWN) {
	ospf_nbr_state_hello(id,intf,nbr);
    }

    nbr_list = &hello->nbr;
    for(nbr_num=0;*nbr_list;nbr_list++,nbr_num++) {
	if(ntohl(*nbr_list) == id) {
	    if(nbr->state < NBR_2WAY) {
		ospf_nbr_state_2way(id,intf,nbr);
	    }
	    my_id_include = TRUE;
	    break;
	}
    }

    if(!my_id_include) {
	ospf_nbr_state_1way(id,intf,nbr);
    }
    else if(intf->type == NONBROADCAST) {
	if(ntohl(hello->dr) == IF_ADDR(nbr->nbr_addr))
	  nbr_is_dr = TRUE;
	if(ntohl(hello->bdr) == IF_ADDR(nbr->nbr_addr))
	  nbr_is_bdr = TRUE;

	if(hello->priority != nbr->priority) {
	    nbr->priority = hello->priority;
	    nbr_change = TRUE;
	}
	else if((nbr_is_dr && !(hello->bdr)) && (intf->state == IFS_WAITING)) {
	    nbr->dr = ntohl(hello->dr);
	    nbr->bdr = ntohl(hello->bdr);
	    backup_seen = TRUE;
	}
	else if(nbr_is_bdr && (intf->state == IFS_WAITING)) {
	    nbr->dr = ntohl(hello->dr);
	    nbr->bdr = ntohl(hello->bdr);
	    backup_seen = TRUE;
	}
	else {
	    if((ntohl(hello->dr) != nbr->dr)
	    && ((nbr->dr == IF_ADDR(nbr->nbr_addr)) || (nbr_is_dr)))
	      nbr_change = TRUE;
	    else if((ntohl(hello->bdr) != nbr->bdr)
		 &&((nbr->bdr == IF_ADDR(nbr->nbr_addr)) || (nbr_is_bdr)))
	      nbr_change = TRUE;
	}

	nbr->dr = ntohl(hello->dr);
	nbr->bdr = ntohl(hello->bdr);

    }

    if(intf->type == NONBROADCAST && !intf->priority && nbr->priority
    && intf->dr != IF_ADDR(nbr->nbr_addr) && intf->bdr != IF_ADDR(nbr->nbr_addr))
      if(intf->send_flag == SEND_OK) ospf_send_hello(id,nbr,intf);

    if(backup_seen) {
	ospf_if_state_backupseen(id,intf);
    }
    else if(nbr_change) {
	ospf_if_state_nbrchange(id,intf);
    }
    
}

/*

  ospf_recv_db

*/
int ospf_recv_db(id,db,intf,src,dst)
u_long id;
struct DB_PKT *db;
struct OSPF_IF *intf;
u_long src;
u_long dst;
{
    struct OSPF_NBR *nbr;
    int event;
    u_short len;

    nbr = intf->nbr;
    len = ntohs(db->hdr.length);
    event = FALSE;
    
    if(IF_ADDR(nbr->nbr_addr) != src) {
	return 0;
    }

    len -= OSPF_HDR_SIZE + DB_PACKET_SIZE;
    switch(nbr->state) {
    case NBR_DOWN:
    case NBR_ATTEMPT:
	return 0;
    case NBR_2WAY:
	return 0;
    case NBR_INIT:
	ospf_nbr_state_2way(id,intf,nbr);
	if(nbr->state != NBR_EXSTART) break;
    case NBR_EXSTART :
      if((db->db_bit & (INIT | MORE | MASTER_SLAVE) && !len)
      && (nbr->nbr_id >id)) {
	  nbr->mode = SLAVE;
	  nbr->bits = 0;
	  nbr->seq = ntohl(db->seq);
	  /*printf("nbr->nbr_id > id\n");*/
	  ospf_nbr_state_negodone(id,intf,nbr);
	  if(nbr->state != NBR_EXCHANGE) {
	      nbr->bits = (INIT | MORE | MASTER_SLAVE);
	      nbr->mode = 0;
	      break;
	  }
	  if(intf->send_flag == SEND_OK) ospf_send_database(id,nbr,intf);
      }
      else if(!(db->db_bit & (INIT | MASTER_SLAVE))
	   && (nbr->seq == ntohl(db->seq))
	   && (nbr->nbr_id < id)) {
	/*printf("nbr->nbr_id < id\n");*/
	  nbr->mode = MASTER;
	  nbr->bits = MASTER_SLAVE;
	  ospf_nbr_state_negodone(id,intf,nbr);	  
	  if(nbr->state != NBR_EXCHANGE) {
	      nbr->bits = (INIT | MORE | MASTER_SLAVE);
	      nbr->mode = 0;
	      break;
	  }
	  if(len) {
	      lsreq_list(id,db,nbr,intf,len);
	  }
	  nbr->seq++;
	  if(intf->send_flag == SEND_OK) ospf_send_database(id,nbr,intf);
      }
      else if(nbr->nbr_id == id) {
      }
      else {
	/*	printf(" else %d, %d\n", nbr->seq, ntohl(db->seq));*/
	/*          if(!intf->rtimer) {
	    if(intf->send_flag == SEND_OK) ospf_send_database(id,nbr,intf);
	    intf->rtimer=timer_init(id,intf,retrans_time_out); 
            timer_set(intf->rtimer, OSPF_RETRANS);
	  };*/
	if(nbr->seq != ntohl(db->seq)) {
	  nbr->seq = ntohl(db->seq);
	  if(intf->send_flag == SEND_OK) ospf_send_database(id,nbr,intf);
        }	  

/*	  if(intf->send_flag == SEND_OK) ospf_send_database(id,nbr,intf);*/
      }
	break;
    case NBR_EXCHANGE :
	if(((db->db_bit & MASTER_SLAVE) && (nbr->mode == MASTER))
	|| (db->db_bit & INIT)) {
	  /*	  printf(" INIT db %d, %d\n", nbr->seq, ntohl(db->seq));*/
	    if(nbr->seq != ntohl(db->seq))
	      ospf_nbr_state_mismatch(id,intf,nbr);
	    break;
	}
	if(nbr->mode == MASTER) {
	    if(nbr->seq == ntohl(db->seq)) {
		nbr->seq++;
		if(len) {
		    lsreq_list(id,db,nbr,intf,len);
		}
		if(!(db->db_bit & MORE) && !lsdb_sum_more(nbr->sum_list->rt_table)) {
		    ospf_nbr_state_exchange(id,intf,nbr);
		}
		else {
		    if(intf->send_flag == SEND_OK) ospf_send_database(id,nbr,intf);
		}
	    }
	    else if(nbr->seq - 1 == ntohl(db->seq)) {
		ospf_nbr_state_mismatch(id,intf,nbr);
	    }
	}
	else {
	    if(nbr->seq + 1 == ntohl(db->seq)) {
		nbr->seq = ntohl(db->seq);
		if(!(db->db_bit & MORE) && !lsdb_sum_more(nbr->sum_list->rt_table)) event = EVT_EXCH_DONE;

		if(len) {
		    lsreq_list(id,db,nbr,intf,len);
		}

		if(intf->send_flag == SEND_OK) ospf_send_database(id,nbr,intf);
		if(event == EVT_EXCH_DONE) {
		    ospf_nbr_state_exchange(id,intf,nbr);		    
		}

	    }
	    else if(nbr->seq == ntohl(db->seq)) {
		if(intf->send_flag == SEND_OK) ospf_send_database(id,nbr,intf);
	    }
	    else {
		ospf_nbr_state_mismatch(id,intf,nbr);
	    }
	}
	break;
    case NBR_LOADING :
    case NBR_FULL:
#ifdef DEBUG
      log_trace(stderr,"nbr->mode : %x, nbr->seq : %x, db->seq : %x\n",
		nbr->mode,nbr->seq,ntohl(db->seq));
#endif
      if(nbr->mode == SLAVE_HOLD && nbr->seq == ntohl(db->seq)) {
	  if(intf->send_flag == SEND_OK) ospf_send_database(id,nbr,intf);
      }
	  else if((nbr->mode == MASTER && nbr->seq == ntohl(db->seq)) ||
	      (nbr->mode == SLAVE && nbr->seq-1 == ntohl(db->seq))) {
/*	  log_trace(stderr,"recv db no plobrem\n");*/
      }
      else{
/*	  log_trace(stderr,"recv db plobrem\n");*/
	  ospf_nbr_state_mismatch(id,intf,nbr);
      }
/*	log_trace(stderr,"recv db \n");*/
	break;
    }

    if(nbr->state >= NBR_EXCHANGE && nbr->req_list != NULL) {
	if(intf->send_flag == SEND_OK) ospf_send_req(id,nbr,intf);
    }
}

/*

  ospf_recv_req

*/
int ospf_recv_req(id,req,intf,src,dst)
u_long id;
struct LS_REQ_PKT *req;
struct OSPF_IF *intf;
u_long src;
u_long dst;
{
    struct OSPF_NBR *nbr;
    int pkt_len,req_len,len,ls_len;
    int update_len,tmp_len;
    struct OSPF_AREA *area;
    byte ls_type;
    u_long ls_id,adv_rt;
    byte *reqp;
    byte *lsdb_sum;
    struct LS_UPDATE_PKT *update;
    int adv_num,adv_len;
    byte *adv,*adv_ptr;
    
    if(intf->state == INTF_DOWN) {
	return 0;
    }

    nbr = intf->nbr;
    pkt_len = ntohs(req->hdr.length);
    area = intf->area;
    
    if(IF_ADDR(nbr->nbr_addr) != src) {
	return 0;
    }

    if(nbr->state < NBR_EXCHANGE)
      return 0;
    
    req_len = pkt_len - OSPF_HDR_SIZE;

    len = OSPF_HDR_SIZE + LS_UPDATE_PACKET_SIZE ;
    OSPF_SEND_ALLOC(update,LS_UPDATE_PKT,len);
    adv = adv_ptr = (byte *)&update->adv;
    adv_num = 0;
    
    reqp = (byte *)&(req->reserve1);
    update_len = OSPF_HDR_SIZE + LS_UPDATE_PACKET_SIZE ;
    
    for(len=0;len<req_len;len+=LS_REQ_PACKET_SIZE) {
	if((req->ls_type < LS_TYPE_RT || req->ls_type > LS_TYPE_ASE)) {
	    printf("Bad LS Req\n");
	    return;
	}
	reqp += sizeof(short);
	reqp += sizeof(byte);
	ls_type = *reqp;
	reqp++;
	bcopy(reqp,&ls_id,sizeof(long));
	reqp+=sizeof(long);
	bcopy(reqp,&adv_rt,sizeof(long));
	reqp+=sizeof(long);

	if((lsdb_sum = search_lsdb_sum_list(area->adv_lsa,ls_type,ntohl(ls_id),ntohl(adv_rt))) == NULL) {
	    ospf_nbr_state_badreq(id,intf,nbr);
	    return;
	}

	tmp_len = LS_LEN(((struct LSDB_SUM_LIST *)lsdb_sum)->lsh);
	
	if(update_len + tmp_len >= INTF_MTU) {
	    break;
	    update->hdr.type = OSPF_LS_UPDATE_PKT;
	    update->adv_num = htonl(adv_num);
	    ospf_send_packet(id,update,update_len,intf);
	    update_len = OSPF_HDR_SIZE + LS_UPDATE_PACKET_SIZE ;
	    OSPF_SEND_ALLOC(update,LS_UPDATE_PKT,update_len);
	    adv = adv_ptr = (byte *)&update->adv;
	    adv_num = 0;
	}
	
	ls_len = get_lsdb_entry(ls_type,(struct LSDB_SUM_LIST *)lsdb_sum,&adv,intf->trans_timer);
	if(!ls_len) continue;
	adv_num++;
	(byte *)adv += ls_len;
	update_len += ls_len;
    }

    update->hdr.type = OSPF_LS_UPDATE_PKT;
    update->adv_num = htonl(adv_num);
    
    ospf_send_packet(id,update,update_len,intf);
}

/*

  ospf_recv_update

*/
int ospf_recv_update(id,update,intf,src,dst)
u_long id;
struct LS_UPDATE_PKT *update;
struct OSPF_IF *intf;
u_long src;
u_long dst;
{
    struct OSPF_NBR *nbr;
    short pkt_len,len,ack_len;
    int adv_num;
    struct LS_HDR *hdr,*adv_hdr;
    struct LS_ACK_PKT *ack;
    union ADV_LSDB *adv;
    struct LS_REQ *req,*pre;
    
    nbr = intf->nbr;
    pkt_len = ntohs(update->hdr.length);

    if(IF_ADDR(nbr->nbr_addr) != src) {
	return 0;
    }

    if(nbr->state < NBR_EXCHANGE)
      return 0;

    pkt_len -= OSPF_HDR_SIZE;
    adv = &update->adv;
    len = OSPF_HDR_SIZE + LS_HDR_SIZE * ntohl(update->adv_num);
    OSPF_SEND_ALLOC(ack,LS_ACK_PKT,len);
    hdr = &ack->lsh;

    ack_len = OSPF_HDR_SIZE;
    for(adv_num=0;adv_num<ntohl(update->adv_num);adv_num++) {
	if(ack_len + LS_HDR_SIZE > INTF_MTU) {
	    ack->hdr.type = OSPF_LS_ACK_PKT;
	    ospf_send_packet(id,ack,ack_len,intf);
	    OSPF_SEND_ALLOC(ack,LS_ACK_PKT,len);
	    hdr = &ack->lsh;
	    ack_len = OSPF_HDR_SIZE;
	}
	adv_hdr = &(adv->rt.hdr);
	bcopy(adv_hdr,hdr,LS_HDR_SIZE);
	hdr++;
	ack_len += LS_HDR_SIZE;
	
	if(nbr->req_list != NULL) {
	    for(req=nbr->req_list;req;req=req->next) {
		if(adv_hdr->ls_type == req->ls_type
		   && adv_hdr->ls_id == req->ls_id
		   && adv_hdr->adv_rt == req->adv_rt ) {
		    	if(req == nbr->req_list)
			   nbr->req_list = req->next;
			else
			   pre->next = req->next;
			free((byte *)req);
		    break;
		}
		pre = req;
	    }
	    
	    if(nbr->req_list == NULL && !lsdb_sum_more(nbr->sum_list->rt_table))
	      ospf_nbr_state_loading(id,intf,nbr);
	}
		
	(byte *)adv += ntohs(adv_hdr->length);
    }

    ack->hdr.type = OSPF_LS_ACK_PKT;

    if(intf->send_flag)
      ospf_send_packet(id,ack,ack_len,intf);

    if(nbr->state > NBR_EXSTART && nbr->req_list == NULL)
      ospf_send_req(id,nbr,intf);
}

/*

  ospf_recv_ack

*/
int ospf_recv_ack(id,ack,intf,src,dst)
u_long id;
struct LS_ACK_PKT *ack;
struct OSPF_IF *intf;
u_long src;
u_long dst;
{
    struct OSPF_NBR *nbr;
    struct OSPF_HDR *o_hdr;
    struct LS_HDR *lsh;

    int pkt_len;
    int bad_ack;
    
    nbr = intf->nbr;
    pkt_len = ntohs(ack->hdr.length);
    bad_ack = 0;
    
    if(IF_ADDR(nbr->nbr_addr) != src) {
	return 0;
    }

    o_hdr = (struct OSPF_HDR *)ack;
    
    pkt_len -= OSPF_HDR_SIZE;
    
    lsh = &ack->lsh;
    for(;pkt_len;pkt_len -= LS_HDR_SIZE) {
	if((lsh->ls_type < LS_TYPE_RT || lsh->ls_type > LS_TYPE_ASE)) {
	    printf("Bad LS TYPE\n");
	}
	
	if(bad_ack=lsdb_change_ack(intf->area->lsdb,lsh)) {
	    lsh++;
	}
	else {
	    printf("ls_hdr_check is not match\n");
	    bad_ack = 0;
	    lsh++;
	}
    }

    if(!bad_ack)
      ospf_send_update(id,nbr,intf,intf->area->lsdb);
}

      
/*

  ospf_packet_dump

*/
void ospf_packet_dump(id,pkt,len,src_addr,dst_addr,action)
u_long id;
byte *pkt;
u_short len;
u_long src_addr;
u_long dst_addr;
char *action;
{
    struct OSPF_HDR *hdr;
    FILE *fp;
    time_t act_time;
    char time_buf[32],all_buff[32];
    u_long rtif;
    u_long src,dst;
    struct RT_IFCONF *my_rtif;
    int pkt_num;
    
    act_time = get_currnt_time();
    strcpy(all_buff,time_to_char(&act_time));
    strncpy(time_buf,&all_buff[4],15);
    time_buf[15] = '\0';

    hdr = (struct OSPF_HDR *)pkt;

    if(!strcmp(action,"SEND"))
      pkt_num = ospf_send_packet_num;
    else
      pkt_num = ospf_recv_packet_num;
	 
    if(id && (fp = get_trace_fp(id))) {
	log_trace(fp,"\n %-8s %s  %s -> ",
	      ((hdr->type < 5) && (hdr->type > 0)) ? pkt_type[hdr->type] : "???",
	      action,inetaddr_to_char(ntohl(src_addr)));
	log_trace(fp,"%s at  %s",
		  inetaddr_to_char(ntohl(dst_addr)),time_buf);
#ifdef VXWORKS
	log_trace(fp," [%d]\n\n",pkt_num);
#else
	log_trace(fp,"\n\n");
#endif
    }
	
    log_trace(stderr,"\n %-8s %s  %s -> ",
	      ((hdr->type < 5) && (hdr->type > 0)) ? pkt_type[hdr->type] : "???",
	     action,inetaddr_to_char(ntohl(src_addr)));
    log_trace(stderr,"%s at %s",
	      inetaddr_to_char(ntohl(dst_addr)),time_buf);
#ifdef VXWORKS
    log_trace(stderr," [%d]\n\n",pkt_num);
#else
    log_trace(stderr,"\n\n");
#endif

    if(!strcmp(action,"SEND")) rtif = src_addr;
    else if(!strcmp(action,"RECV")) {
	if(dst_addr == OSPF_ALLSPF_ADDR || dst_addr == OSPF_ALLDR_ADDR) {
	    my_rtif = get_local_rtif(src_addr);
	    if(my_rtif)
	      rtif = IF_ADDR(my_rtif->local_addr);
	    else
	      rtif = src_addr;
	}
	else
	  rtif = dst_addr;
    }
    else rtif = 0;
    
    switch(hdr->type) {
    case OSPF_HELLO_PKT : ospf_hello_dump(fp,(struct HELLO_PKT *)pkt,len);
	if(display_ok(id,rtif,hdr->type))
	  ospf_hello_dump(stderr,(struct HELLO_PKT *)pkt,len);
	break;
    case OSPF_DB_PKT : ospf_db_dump(fp,(struct DB_PKT *)pkt,len);
	if(display_ok(id,rtif,hdr->type))
	  ospf_db_dump(stderr,(struct DB_PKT *)pkt,len);
	break;
    case OSPF_LS_REQ_PKT : ospf_req_dump(fp,(struct REQ_PKT *)pkt,len);
	if(display_ok(id,rtif,hdr->type))
	  ospf_req_dump(stderr,(struct REQ_PKT *)pkt,len);
	break;
    case OSPF_LS_UPDATE_PKT : ospf_update_dump(fp,(struct UPDATE_PKT *)pkt,len);
	if(display_ok(id,rtif,hdr->type))
	  ospf_update_dump(stderr,(struct UPDATE_PKT *)pkt,len);
	break;
    case OSPF_LS_ACK_PKT : ospf_ack_dump(fp,(struct ACK_PKT *)pkt,len);
	if(display_ok(id,rtif,hdr->type))
	  ospf_ack_dump(stderr,(struct ACK_PKT *)pkt,len);
	break;
	default : break;
    }
}

/*

  ospf_hello_dump

*/
void ospf_hello_dump(fp,hello,pkt_len)
FILE *fp;
struct HELLO_PKT *hello;
u_short pkt_len;
{
    u_long *nbr;
    u_short len;

    if(fp == NULL || hello == NULL)
      return ;
    
    ospf_hdr_dump(fp,&hello->hdr);

    log_trace(fp," Netmask = %s\n",inetaddr_to_char(hello->netmask));
    log_trace(fp," Options : ");
    if(hello->options & T_OPTION) log_trace(fp," TOS ");
    if(hello->options & E_OPTION) log_trace(fp," Externals ");
    log_trace(fp,"\n");
    log_trace(fp," Hello_int  %d   Dead_int  %ld\n",ntohs(hello->hello_int),ntohl(hello->dead_int));
    log_trace(fp," Priority %d\n",hello->priority);
    log_trace(fp," DR : %s    ",inetaddr_to_char(hello->dr));
    log_trace(fp," BDR :%s\n",inetaddr_to_char(hello->bdr));    

    len = pkt_len - OSPF_HDR_SIZE - HELLO_PACKET_SIZE;
    
    nbr = &(hello->nbr);
    for(;len;len-=sizeof(long)) {
	log_trace(fp," Neighbor = %s\n",inetaddr_to_char(*nbr));
	nbr++;
    }

}

/*

  ospf_db_dump

*/
void ospf_db_dump(fp,dbp,pkt_len)
FILE *fp;
struct DB_PKT *dbp;
short pkt_len;
{
    struct LS_HDR *hdr;
    short len;
    short db_len;

    if(fp == NULL || dbp == NULL)
      return ;

    ospf_hdr_dump(fp,&dbp->hdr);
    
    db_len = pkt_len - OSPF_HDR_SIZE - DB_PACKET_SIZE;
    log_trace(fp," Options : ");
    if(dbp->options & T_OPTION) log_trace(fp," TOS ");
    if(dbp->options & E_OPTION) log_trace(fp," Externals ");
    log_trace(fp,"\n");
    log_trace(fp," Flag : ");
    if(dbp->db_bit & INIT) log_trace(fp," Init ");
    if(dbp->db_bit & MORE) log_trace(fp," More ");
    if(dbp->db_bit & MASTER_SLAVE) log_trace(fp," M/S ");
    log_trace(fp,"\n Seq : %x\n",ntohl(dbp->seq));
    hdr = &(dbp->db);
    for(len=0;len<db_len;len+=LS_HDR_SIZE) {
	ls_hdr_dump(fp,hdr);
	hdr++;
    }
}

/*

  ospf_req_dump

*/
void ospf_req_dump(fp,req,pkt_len)
FILE *fp;
struct LS_REQ_PKT *req;
short pkt_len;
{
    struct LS_HDR hdr;
    short len;
    short req_len;
    byte *reqp;

    if(fp == NULL || req == NULL)
      return ;

    ospf_hdr_dump(fp,&req->hdr);

    req_len = pkt_len - OSPF_HDR_SIZE;
    reqp = (byte *)&(req->reserve1);
    for(len=0;len<req_len;len+=LS_REQ_PACKET_SIZE) {
	 reqp += sizeof(short);
	 reqp += sizeof(byte);
	 hdr.ls_type = *reqp;
	 reqp++;
	 bcopy(reqp,&(hdr.ls_id),sizeof(long));
	 reqp+=sizeof(long);
	 bcopy(reqp,&(hdr.adv_rt),sizeof(long));
	 reqp+=sizeof(long);
	 hdr.length = 0;
	 ls_hdr_dump(fp,&hdr);
     }
}

/*

  ospf_updata_dump

*/
void ospf_update_dump(fp,update,pkt_len)
FILE *fp;
struct LS_UPDATE_PKT *update;
int pkt_len;
{
    struct LS_HDR *hdr;
    int ls_len;
    int adv_num;
    union ADV_LSDB *adv;
    
    if(fp == NULL || update == NULL)
      return ;

    ospf_hdr_dump(fp,&update->hdr);

    adv = &update->adv;
    ls_len = pkt_len - OSPF_HDR_SIZE - LS_UPDATE_PACKET_SIZE;
    for(adv_num=0;adv_num<ntohl(update->adv_num);adv_num++) {
	hdr = &adv->rt.hdr;
	switch((int)hdr->ls_type) {
	case LS_TYPE_RT : ls_rt_dump(fp,&adv->rt);
	    break;
        case LS_TYPE_NET :ls_net_dump(fp,&adv->net);
	    break;
        case LS_TYPE_SUM_NET : ls_sum_dump(fp,&adv->sum);
	    break;
        case LS_TYPE_SUM_ASBR : ls_sum_dump(fp,&adv->sum);
	    break;
	case LS_TYPE_ASE : ls_ase_dump(fp,&adv->ase);
	    break;
	default :
	    break;
        }
	
	(byte *)adv = (byte *)adv + ntohs(hdr->length);
    }
    log_trace(fp,"\n");
}

/*

  ospf_ack_dump

*/
void ospf_ack_dump(fp,ack,pkt_len)
FILE *fp;
struct LS_ACK_PKT *ack;
short pkt_len;
{
    struct LS_HDR *hdr;
    short len;
    short sum_len;
    
    if(fp == NULL || ack == NULL)
      return ;

    ospf_hdr_dump(fp,&ack->hdr);

    sum_len = pkt_len - OSPF_HDR_SIZE;
    hdr = &(ack->lsh);
    for(len=0;len<sum_len;len+=LS_HDR_SIZE) {
	ls_hdr_dump(fp,hdr);
	hdr++;
    }
}

/*

  ospf_hdr_dump

*/
void ospf_hdr_dump(fp,hdr)
FILE *fp;
struct OSPF_HDR *hdr;
{
    byte *auth;
    
    if(fp == NULL || hdr == NULL)
      return ;

    log_trace(fp," Version : %d   Length : %d \n",hdr->ver,ntohs(hdr->length));
    log_trace(fp," TYPE : %s",
    ((hdr->type < 5) && (hdr->type > 0)) ? pkt_type[hdr->type] : "???");
    log_trace(fp," Router ID : %s",inetaddr_to_char(hdr->rt_id));
    log_trace(fp,"     Area ID : %s\n",inetaddr_to_char(hdr->area_id));
    log_trace(fp," Checksum : %x",ntohs(hdr->chcksum));

     /* The following line causes RPS to dump core when using
      *  authentication, and in a few other situations. 
      */
    /* log_trace(fp,"   Authtype : %s",auth_type[hdr->authtype]); */
    auth = (byte *)hdr->auth;
    log_trace(fp,"     Authkey  : %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x",
	       *auth,*(auth+1),*(auth+2),*(auth+3),*(auth+4),
	       *(auth+5),*(auth+6),*(auth+7));
/*    log_trace(fp,"%s",inetaddr_to_char(hdr->auth[1]));*/
    log_trace(fp,"\n\n");
}


void bin_dump(pkt,pkt_len)
byte *pkt;
int pkt_len;
{
    int len;
    byte *buf;

    buf = pkt;
    for(len=0;len<pkt_len;len++) {
	printf(" %x ",*buf++);
    }
    printf("\n");
}

