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

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>

char ipstr1[19];
char ipstr2[19];
char ipstr3[19];
char ipstr4[19];

#define MODX 4102

/*
 * in_cksum()
 * Checksum routine for Internet Protocol family headers (C Version)
 */
in_cksum(addr, len)
unsigned short *addr;
int len;
{
    register int nleft = len;
    register unsigned short *w = addr;
    register int sum = 0;
    unsigned short answer = 0;

    /*
     * Our algorithm is simple, using a 32 bit accumulator (sum), we add
     * sequential 16 bit words to it, and at the end, fold back all the
     * carry bits from the top 16 bits into the lower 16 bits.
     */
    while (nleft > 1)  {
	sum += *w++;
	nleft -= 2;
    }

    /* mop up an odd byte, if necessary */
    if (nleft == 1) {
	*(unsigned char *)(&answer) = *(unsigned char *)w ;
	sum += answer;
    }
    
    /* add back carry outs from top 16 bits to low 16 bits */
    sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
    sum += (sum >> 16);                     /* add carry */
    answer = ~sum;                          /* truncate to 16 bits */
    return(answer);
}


/*
 * encodecc()
 * Fletcher checksum algorithm
 */
encodecc( mess,len,k )
unsigned char mess[] ;    /* the TPDU to be checksummed */
int      len;             /* position of first checksum octet
int      k;                  as an offset from mess[0]  */
{
    int ip,iq,ir,c0,c1;
    unsigned char *p,*p1,*p2,*p3 ;

    p = mess ;
    p3 = mess + len ;

    if (k > 0) { mess[k-1] = 0x00 ; mess[k] = 0x00 ; }
            /* insert zeros for checksum octets */

    c0 = 0 ;
    c1 = 0 ;
    p1 = mess ;
    while (p1 < p3) {   /* outer sum accumulation loop */
        p2 = p1 + MODX ;
	if (p2 > p3) p2 = p3 ;
        for (p = p1 ; p < p2 ; p++) { /*  inner sum accumulation loop */
	     c0 = c0 + (*p) ;
	     c1 = c1 + c0 ;
	}
        c0 = c0%255 ;
	c1 = c1%255 ;
	p1 = p2 ;
	/* adjust accumulated sums to mod 255 */
    }
    ip = (c1 << 8) + c0 ;     /* concatenate c1 and c0 */

    if (k > 0)	{     /* compute and insert checksum octets */
	iq = ((len-k)*c0 - c1)%255 ; if (iq <= 0) iq = iq + 255 ;
	mess[k-1] = iq ;
	ir = (510 - c0 - iq) ;
	if (ir > 255) ir = ir - 255 ; mess[k] = ir ;
    }
    return(ip) ;
}


/*

  char_to_inetaddr - convert dot-notation character to address

*/
u_long char_to_inetaddr(addr)
char *addr;
{
    struct in_addr iaddr;
    struct hostent *haddr;
    char *buf,num[16];
    int i;
    int bits;

    i = iaddr.s_addr = bits = 0;

    for(buf = addr;*buf!=NULL;buf++) {
	if(*buf == '.') {
	    num[i] = '\0';
	    iaddr.s_addr <<= 8 ;
	    iaddr.s_addr |= atoi(num);
	    i =0;
	    bits += 8;
	}
	else {
	    num[i++] = *buf;
	}
    }
    num[i] = '\0';
    iaddr.s_addr <<= 8;
    iaddr.s_addr |= atoi(num);
    bits += 8;
    
    if(bits < 32) iaddr.s_addr <<= 32-bits;
    return iaddr.s_addr;
}

/*

  inetaddr_to_char

*/
char *inetaddr_to_char(addr)
u_long addr;
{
    struct in_addr iaddr;
    char *c_addr;
    
    bzero(&iaddr,sizeof(struct in_addr));
    iaddr.s_addr = addr;
    c_addr = inet_ntoa(iaddr);
    
    return(c_addr);
}


int mask_bits(net,mask)
u_long net;
u_long mask;
{
    int masklen;
    int tmp;

    masklen=0;
    tmp = mask;
    while(tmp) {
        if(tmp & 0x80000000) masklen++;
	tmp = tmp << 1;
    }

    return masklen;
}


void prefix_parse(token, addr, mask)
char *token;
u_long *addr;
u_long *mask;
{
    char *tp,buf[16];
    int ctr;
    int len;
    u_long bit;

    bzero(buf, sizeof(buf));
    for(tp=token,ctr=0;*tp;tp++,ctr++) {
        if(*tp == '/')  break;
        else            buf[ctr] = *tp;
      }

    if(!(*tp)) {
        *addr = char_to_inetaddr(token);
        *mask = 0;
        return;
      }

    buf[ctr] = '\0';
    *addr = char_to_inetaddr(buf);

    len = atoi(++tp);

    bit = 0x80000000;
    while(--len) {
        bit >>= 1;
        bit |= 0x80000000;
      }
    *mask = bit;

    return;
}  

void sg_entry_parse(token, src, grp)
char *token;
u_long *src;
u_long *grp;
{
    char *tp,buf[16];
    int ctr;
    int len,i;

    /* 
     *  get src_addr
     */
    bzero(buf, sizeof(buf));
    for(tp=token,ctr=0;*tp;tp++,ctr++) {
        if(*tp == '/')  break;
        else            buf[ctr] = *tp;
    }

    if(!(*tp)) {
        *src = char_to_inetaddr(token);
        *grp = 0;
        return;
    }

    buf[ctr] = '\0';
    *src = char_to_inetaddr(buf);

    /*
     * get group_addr
     */
    bzero(buf, sizeof(buf));
    tp++;
    for(ctr=0;*tp;tp++,ctr++) {
        buf[ctr] = *tp;
    }

    buf[ctr] = '\0';
    *grp = char_to_inetaddr(buf);

    return;
}  

char *inet_atos(addr)
u_long addr;
{
    static char str[18];
    char *p;

    p = (char *)&addr;

    (void) snprintf(str, sizeof(str),
		    "%d.%d.%d.%d",0xff&p[0],0xff&p[1],0xff&p[2],0xff&p[3]);
    return str;
}

/*

  inet_stoa - convert dot-notation character to address

*/
u_long inet_stoa(addr)
char *addr;
{
    struct in_addr iaddr;
    struct hostent *haddr;
    char *buf,num[16];
    int i;
    int bits;

    i = iaddr.s_addr = bits = 0;

    for(buf = addr;*buf!=NULL;buf++) {
	if(*buf == '.') {
	    num[i] = '\0';
	    iaddr.s_addr <<= 8 ;
	    iaddr.s_addr |= atoi(num);
	    i =0;
	    bits += 8;
	}
	else {
	    num[i++] = *buf;
	}
    }
    num[i] = '\0';
    iaddr.s_addr <<= 8;
    iaddr.s_addr |= atoi(num);
    bits += 8;
    
    if(bits < 32) iaddr.s_addr <<= 32-bits;
    return iaddr.s_addr;
}

char *inet_ipstr(addr,buf)
u_long addr;
char buf[];
{
    char *p;

    p = (char *)&addr;
    (void) sprintf(buf, 
		    "%d.%d.%d.%d",0xff&p[0],0xff&p[1],0xff&p[2],0xff&p[3]);
    return buf;
}

