/*
 * |-----------------------------------------------------------|
 * | Copyright (c) 1991, 1990 MIPS Computer Systems, Inc.      |
 * | All Rights Reserved                                       |
 * |-----------------------------------------------------------|
 * |          Restricted Rights Legend                         |
 * | Use, duplication, or disclosure by the Government is      |
 * | subject to restrictions as set forth in                   |
 * | subparagraph (c)(1)(ii) of the Rights in Technical        |
 * | Data and Computer Software Clause of DFARS 252.227-7013.  |
 * |         MIPS Computer Systems, Inc.                       |
 * |         950 DeGuigne Avenue                               |
 * |         Sunnyvale, California 94088-3650, USA             |
 * |-----------------------------------------------------------|
 */
#ident	"$Header: rt_nss.c,v 1.3.2.1 92/06/24 13:39:16 marker Exp $"
/*
 *   CENTER FOR THEORY AND SIMULATION IN SCIENCE AND ENGINEERING
 *			CORNELL UNIVERSITY
 *
 *      Portions of this software may fall under the following
 *      copyrights: 
 *
 *	Copyright (c) 1983 Regents of the University of California.
 *	All rights reserved.  The Berkeley software License Agreement
 *	specifies the terms and conditions for redistribution.
 *
 *  GATED - based on Kirton's EGP, UC Berkeley's routing daemon (routed),
 *	    and DCN's HELLO routing Protocol.
 */

#ifndef	lint
static char *rcsid = "$Header: rt_nss.c,v 1.3.2.1 92/06/24 13:39:16 marker Exp $";
#endif	not lint

 /*
 * Some modified from Routing Table Management Daemon routed/tables.c.
 *
 */

#include "include.h"

#ifdef	NSS
/*
 * Add a route for the virtual interface route by using the IP address
 * specified for the hostid.
 *
 */
addrouteforbackbone()
{
  struct sockaddr_in gateway;
  struct interface *ifp;
    
  bzero((char *)&gateway, sizeof (gateway));
  gateway.sin_family = AF_INET;
  gateway.sin_addr.s_addr = gethostid();
  if ((ifp = if_withnet(&gateway)) == NULL) {
    TRACE_EXT("addrouteforbackbone: no interface for %s\n", inet_ntoa(gateway.sin_addr));
    return;
  } else {
    addrouteforif(ifp);
  }
}


/*
 * Returns EGP routes metric distribution
 */
egp_metric_distrib(metric_dist, max_metric)
int	*metric_dist;
int	max_metric;
{
	struct rt_entry	*rt;
	struct rthash	*rh;

	bzero((char *) metric_dist, sizeof(int) * max_metric);

	for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) {
		for (rt = rh->rt_forw; rt != (struct rt_entry *) rh; rt = rt->rt_forw) {
			if ((rt->rt_state & RTS_EXTERIOR) == 0)
				continue;
			if (rt->rt_proto != RTPROTO_EGP)
				continue;
			if (rt->rt_metric > max_metric) {
				TRACE_INT("egp_metric_distrib: max_metric %d, rt_metric %d\n",
					max_metric, rt->rt_metric);
				continue;
			}
			metric_dist[rt->rt_metric]++;
		}
	}
}


struct rt_entry *
rt_lookupnext(dst)
struct sockaddr_in *dst;
{
		
	struct rt_entry	*rt;
	struct rthash	*rh;
	struct sockaddr_in	*rtdst;
	static struct rt_entry	*rt_table = NULL;
	int	i;
	int					rt_compar();


	if (rttable_changed) {
		rttable_changed = 0;
		if (rt_table != NULL)
			free((char *) rt_table);
		rt_table = (struct rt_entry *) calloc(n_routes, sizeof(struct rt_entry));
		if (rt_table == NULL) {
			syslog(LOG_ERR, "rt_lookupnext malloc failed");
			return(NULL);
		}
		for (i = 0, rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++) {
			for (rt = rh->rt_forw; rt != (struct rt_entry *) rh; rt = rt->rt_forw) {
				bcopy((char *) rt, (char *) &rt_table[i++], sizeof(*rt));
				if (i > n_routes) {
					syslog(LOG_ERR, "rt_lookupnext n_routes = %d is too small", 
						n_routes);
					return(NULL);
				}
			}
		}

		if (i != n_routes) {
			syslog(LOG_ERR, "rt_lookupnext n_routes = %d, i = %d",
				n_routes, i);
			return(NULL);
		}
		qsort((char *) rt_table, n_routes, sizeof(struct rt_entry), rt_compar);
	}

	for (i = 0; i < n_routes; i++) {
		rtdst = (struct sockaddr_in *) &rt_table[i].rt_dst;
		if (dst->sin_addr.s_addr < rtdst->sin_addr.s_addr) {
			break;
		}
	}

	/*
	 * Check End Of Table first
	 */
	if (i == n_routes)
		return(NULL);
	else
		return(&rt_table[i]);

}

rt_compar(rt1, rt2)
struct rt_entry	*rt1, *rt2;
{
	struct sockaddr_in	*rt_dst1 = (struct sockaddr_in *) &rt1->rt_dst;
	struct sockaddr_in	*rt_dst2 = (struct sockaddr_in *) &rt2->rt_dst;

	if (rt_dst1->sin_addr.s_addr < rt_dst2->sin_addr.s_addr)
		return(-1);
	else
	if (rt_dst1->sin_addr.s_addr > rt_dst2->sin_addr.s_addr)
		return(1);
	else {
		if (rt1->rt_metric < rt2->rt_metric)
			return(-1);
		else
		if (rt1->rt_metric > rt2->rt_metric)
			return(1);
		else {
			if (rt1->rt_proto == RTPROTO_IGP)
				return(-1);
			else
				return(1);
		}
	}
}


/*
 * igp_sanity_chk() checks whether a particular IGP route is sane
 */
igp_sanity_chk(rt)
  struct rt_entry *rt;
{
  struct rt_entry *old_rt;
	if (!find_es_pdu(rt)) { 
		old_rt = rt;
		rt = rt->rt_back;
		rt_delete(old_rt, KERNEL_INTR);
		return(1);
	}
	else
		return(0);
}
#endif	NSS
