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

#include "defs.h"

struct vif {
    u_long lcl_addr;
    u_long rmt_addr;
    u_long netmask;
    struct if_info *ifap;
    struct dvmrp_nbr *nbrs;
};

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;
};


#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 NET_LIST *network_list=NULL;

void route_init()
{
    /* */
}

/*
 *
 */
void create_network_list(id,addr,mask,metric)
u_long id;
u_long addr;
u_long mask;
int metric;
{
    struct NET_LIST *net,*new_net;
    struct ROUTE *rt,*new_rt;

    for(net=network_list;net!=NULL;net=net->next) {
	if(net->id == id) break;
    }

    if(!net) {
        MALLOC(new_net,NET_LIST);
	new_net->id = id;

	if(!network_list) network_list = new_net;
	else {
	    for(net=network_list;net->next!=NULL;net=net->next);
	    net->next = new_net;
	}

	MALLOC(new_rt,ROUTE);
	new_net->routes = new_rt;
    }
    else {
	for(rt=net->routes;rt->next!=NULL;rt=rt->next) ;
	MALLOC(new_rt,ROUTE);
	rt->next = new_rt;
    }

    new_rt->addr = addr;
    new_rt->mask = mask;
    new_rt->metric = metric;
    new_rt->state = UP;
}

/* 
 *
 */
void generate_network_list(id,net,mask,metric,net_num)
u_long id;
u_long net;
u_long mask;
int metric;
int net_num;
{
    u_long start_net;
    struct in_addr iaddr,imask;
    u_long i;
    int mask_len,host_len;
    u_long bit;

    i=mask;
    mask_len = 0;
    while(0x80000000 & i) {
        mask_len++;
	i <<= 1;
    }
    host_len = 32 - mask_len;
    bit = 0x00000001 << host_len;
    imask.s_addr = htonl(mask);

    start_net = net;
    for(i=0;i<net_num;i++) {
        if((start_net & 0xff000000) == 0xff000000
	|| (start_net & 0x00ff0000) == 0x00ff0000
	|| (start_net & 0x0000ff00) == 0x0000ff00) {
	    start_net += bit;
	    continue;
	}
        iaddr.s_addr = htonl(start_net);
	create_network_list(id,start_net, mask,metric);
        start_net += bit;
    }

}

/*
 *
 */
void add_network(id,addr,mask,metric)
int id;
u_long addr,mask;
int metric;
{
    struct NET_LIST *net;
    struct ROUTE *rt;

    for(net=network_list;net!=NULL;net=net->next) {
	if(net->id == id) break;
    }

    if(!net) {
	printf(" No define network-list %d\n",id);
	return;
    }

    for(rt=net->routes;rt!=NULL;rt=rt->next) {
	if(rt->addr == addr && rt->mask == mask) {
	    rt->state = UP;
	    rt->metric = metric;
	    return ;
	}
    }
    if(!rt) {
	create_network_list(id,addr,mask,metric);
    }
}

/*
 *
 */
void delete_network(id,addr,mask,metric)
int id;
u_long addr,mask;
int metric;
{
    struct NET_LIST *net;
    struct ROUTE *rt;

    for(net=network_list;net!=NULL;net=net->next) {
	if(net->id == id) break;
    }

    if(!net) {
	printf(" No define network-list %d\n",id);
	return;
    }

    for(rt=net->routes;rt!=NULL;rt=rt->next) {
	if(rt->addr == addr && rt->mask == mask) {
	    rt->state = DOWN;
	    rt->metric = 32;
	    return ;
	}
    }
    if(!rt) {
	printf(" No define routes  on network-list %d\n",id);
    }
}

/*
 *
 */
void change_network(id,addr,mask,metric)
int id;
u_long addr,mask;
int metric;
{
    struct NET_LIST *net;
    struct ROUTE *rt;

    for(net=network_list;net!=NULL;net=net->next) {
	if(net->id == id) break;
    }

    if(!net) {
	printf(" No define network-list %d\n",id);
	return;
    }

    for(rt=net->routes;rt!=NULL;rt=rt->next) {
	if(rt->addr == addr && rt->mask == mask) {
	    rt->state = UP;
	    rt->metric = metric;
	    return ;
	}
    }
    if(!rt) {
	printf(" No define routes  on network-list %d\n",id);
    }
}

	    
void network_add(id)
u_long id;
{

    /* */

}
    
struct ROUTE *get_route_list(id)
u_long id; /* network list id */
{
    struct NET_LIST *net;
    struct ROUTE *rt;

    for(net=network_list;net!=NULL;net=net->next) {
	if(net->id == id) break;
    }
    if(net) 
	return net->routes;
    else
	return NULL;
}

struct ROUTE *route_search(list,net,mask,metric)
struct ROUTE *list;
u_long net,mask;
int metric;
{
    struct ROUTE *rt;

    if(!list) return NULL;

    for(rt=list;rt!=NULL;rt=rt->next) {
	if(rt->addr == net && rt->mask == mask) {
	    if(rt->metric == 32) return rt;
	    else {
	        if(rt->metric == metric) 
		    return rt;
	    }
	}
    }

    return rt;
}
	
void network_dump()
{
    struct NET_LIST *net;
    struct ROUTE *rt;

    printf("\n");
    for(net=network_list;net!=NULL;net=net->next) {
	trace(stderr," Network %d \n",net->id);
	for(rt=net->routes;rt!=NULL;rt=rt->next) {
	    trace(stderr," \t Addr: %s",inetaddr_to_char(htonl(rt->addr)));
	    trace(stderr," Mask: %s Metric %d\n",
		  inetaddr_to_char(htonl(rt->mask)),rt->metric);
	}
    }
}

