/* 
 * $Id: idrp_rt_iso.c,v 1.2 1995/08/01 20:26:16 sjr Exp $
 * Merit IDRP release 1.1 (gated 3.5.4).  Copyright (c) 1994 by Merit Network, Inc. 
 */

#include "include.h"
#include "iso.h"
#include "idrp.h"

/* idrp_rt_iso.c - iso specific idrp routes
 *
 * hopefully these routes will migrate to
 * iso generic routines
 *
 *  
 * %% generic iso routines - replace these with Jeff's
 * 
 *  idrp_iso_sockaddr_mask - create bit mask for iso address
 *  idrp_set_iso_sockun(p_sock,iso_len,p_addr) - set iso sockaddr un iso_addr 
 *  sockun_to_prefix(p_dest,p_mask,p_pfx) - sockaddr_un iso to iso_prefix
 */


/* %% idrp iso processing routines */  
 
/* no automatic  aggregate initialization for idrp_iso_sockaddr_mask func */ 
int bit_pattern[] = { 
	0x00,
	0x01,
	0x02,
	0x04,
	0x08,
	0x10,
	0x20,
	0x40,
	0x80};

void
idrp_iso_sockaddr_mask(mask,cnt)
sockaddr_un	*mask;
int cnt;
{
int octet = 0;
int byte_cnt = 0;
int left_over = 0;

	byte_cnt = cnt/8;	
	for (octet = 0; octet < byte_cnt; octet++)
		{
		mask->iso.siso_addr[octet] =  0xff;
		}
	left_over = cnt - (cnt/8)*8;
	if (left_over)
		{
		byte_cnt++;
		}
	mask->iso.siso_family = AF_ISO;	
	mask->iso.siso_len = byte_cnt + 2;
	mask->iso.siso_addr[(cnt/8 + 1)] =  bit_pattern[left_over];
	return;
}

/* there must be a better way to do this sockaddr stuff from
 * a prefix - so look for Jeff's and Steve's code
 * to replace this
 * - hack this in now so that we can on to testing the
 *   IP-> idrp route insertion
 */ 

 /* no automatic aggregate initialization within func idrp_ip_sockaddr_mask */
u_long bit_pattern_idrp_ip_sockaddr_mask[] = {
        (u_long) 0x00,                   /* zero bits */
        (u_long) 0x80000000,             /* 1 bit */
        (u_long) 0xC0000000,             /* 2 bit */
        (u_long) 0xE0000000,             /* 3 bit */
        (u_long) 0xF0000000,             /* 4 bit */
        (u_long) 0xF8000000,             /* 5 bit */
        (u_long) 0xFC000000,             /* 6 bit */
        (u_long) 0xFE000000,             /* 7 bit */
        (u_long) 0xFF000000,             /* 8 bit */
        (u_long) 0xFF800000,             /* 9 bit */
        (u_long) 0xFFC00000,             /* 10 bit */
        (u_long) 0xFFE00000,             /* 11 bit */
        (u_long) 0xFFF00000,             /* 12 bit */
        (u_long) 0xFFF80000,             /* 13 bit */
        (u_long) 0xFFFC0000,             /* 14 bit */
        (u_long) 0xFFFE0000,             /* 15 bit */
        (u_long) 0xFFFF0000,             /* 16 bit */
        (u_long) 0xFFFF8000,             /* 17 bit */
        (u_long) 0xFFFFC000,             /* 18 bit */
        (u_long) 0xFFFFE000,             /* 19 bit */
        (u_long) 0xFFFFF000,             /* 20 bit */
        (u_long) 0xFFFFF800,             /* 21 bit */
        (u_long) 0xFFFFFC00,             /* 22  bit */
        (u_long) 0xFFFFFE00,             /* 23 bit */
        (u_long) 0xFFFFFF00,             /* 24 bit */
        (u_long) 0xFFFFFF80,             /* 25 bit */
        (u_long) 0xFFFFFFC0,             /* 26 bit */
        (u_long) 0xFFFFFFE0,             /* 27 bit */
        (u_long) 0xFFFFFFF0,             /* 28 bit */
        (u_long) 0xFFFFFFF8,             /* 29 bit */
        (u_long) 0xFFFFFFFC,             /* 30 bit */
        (u_long) 0xFFFFFFFE,             /* 31 bit */
        (u_long) 0xFFFFFFFF              /* 32 bit */
        };

void
idrp_ip_sockaddr_mask(mask,cnt)
sockaddr_un	*mask;
int cnt;
{
int left_over;
   
        mask->in.sin_addr.s_addr =  bit_pattern_idrp_ip_sockaddr_mask[cnt];

	mask->in.sin_port = 0;
	mask->in.sin_family = AF_INET;
	left_over = cnt - (cnt/8)*8; 
	if (cnt)
		{
		mask->in.sin_len = (cnt/8) + 4;
		}
	else
		{
		/* set the default to length and family */ 
		mask->in.sin_len = 2;
		} 
	if (left_over)
		{
		mask->in.sin_len += 1 ;
		}
}


/* copy of the set_iso_sockaddr from the isis code
 * - once I get it working, it should be merged into
 *   common iso routines with Steve Hemlich's is-is
 */


void
idrp_set_iso_sockun(p_sock,iso_len,p_addr)
sockaddr_un	*p_sock;
int	iso_len;
u_char	*p_addr;
{
	p_sock->iso.siso_len = iso_len + 2;
	p_sock->iso.siso_family = AF_ISO;
	if (iso_len == 0)
		{
		/* default route => clear siso_len */
		p_sock->iso.siso_len = 0;
		}
	bcopy(p_addr,&p_sock->iso.siso_addr,iso_len);

}

void
sockun_to_prefix(p_dest,p_mask,p_pfx)
sockaddr_un		*p_dest;
sockaddr_un		*p_mask;
struct	iso_prefix	*p_pfx;
{
u_int	c;
int	len;
	
	bzero(p_pfx,sizeof(struct iso_prefix));

	switch(p_dest->a.sa_family)
		{
		case AF_INET:
			if (p_mask->in.sin_len == 2)
				{
				/* default route - set length to zero
				 * - two gives length and family
				 */ 
				len = 0;
				}
			else
				{
				/* take away length (1), family (1)
				 * port (2)
				 */
 
				len = p_mask->a.sa_len - 4; 
				p_pfx->pfx_len = sockun_ipbits(p_mask->in.sin_addr.s_addr);
				}
			bcopy(&p_dest->in.sin_addr,&p_pfx->pfx[0],len);
			break;	
	
		case AF_ISO:
			len = p_mask->a.sa_len - 2;
			p_pfx->pfx_len = len * 8 + sockun_isobits(p_mask->a.sa_data[len]);
			bcopy(&p_dest->iso.siso_addr,&p_pfx->pfx[0],len);
			break;

		}
}

int
sockun_isobits(iso_byte)
u_char  iso_byte;
{
u_int	c;
int	nbit, i;
 

	/* here test the last byte for bits to add to prefix sockaddr
	 * -need to see if Jeff's can make it go faster
	 */

	c = (u_int) iso_byte;
	nbit = 0;
	for (i = 0; i < 8; i++)
		{
		/* bit shift c until it is zero */
		c = c>> 1;
		if (!c)
			{
			nbit = i;
			break;
			}
		}  	
	return (nbit);
}	
		
int
sockun_ipbits(ip_byte)
u_long ip_byte;
{
u_int	c;
int	nbit, i;
 
	/* here test the last byte for bits to add to prefix sockaddr
	 * -need to see if Jeff's can make it go faster
	 */

	c = htonl(ip_byte);
	nbit = 0;
	for (i = 1; i < 33; i++)
		{
		/* bit shift c until it is zero */
		c = c<< 1;
		if (!c)
			{
			nbit = i;
			break;
			}
		}
	return(nbit);
}  	

