/*
* Copyright c                  Realtek Semiconductor Corporation, 2002  
* All rights reserved.                                                
* 
* Program : utility
*
* Original Creator: Edward Jin-Ru Chen 2002/4/29
* $Author $
*
* $Revision: 1.1 $
* $Id: utility.c,v 1.1 2012/10/24 04:18:57 ikevin362 Exp $
* $Log: utility.c,v $
* Revision 1.1  2012/10/24 04:18:57  ikevin362
* initial version
*
* Revision 1.4  2006/01/10 05:53:05  rupert
* * fix inet_addr
*
* Revision 1.3  2005/07/20 15:29:38  yjlou
* +: porting Model Code to Linux Kernel: check RTL865X_MODEL_KERNEL.
*
* Revision 1.2  2004/03/03 10:40:38  yjlou
* *: commit for mergence the difference in rtl86xx_tbl/ since 2004/02/26.
*
* Revision 1.1  2004/02/25 14:27:24  chhuang
* *** empty log message ***
*
* Revision 1.4  2004/02/18 13:12:21  chenyl
* *** empty log message ***
*
* Revision 1.2  2004/02/17 13:01:47  chenyl
* *** empty log message ***
*
* Revision 1.1  2004/02/13 05:18:47  chenyl
* + Pkt generating functions
*
* Revision 1.7  2002/09/27 15:45:49  waynelee
* -> hex2bin
*
* Revision 1.6  2002/09/21 09:54:24  waynelee
* add pkt_aton()
*
* Revision 1.5  2002/09/16 07:31:15  waynelee
* support IPX (experimental)
*
*/

#include "utility.h"
#include <net/rtl/rtl_types.h>


#if defined(RTL865X_TEST) || defined(RTL865X_MODEL_USER) || defined(RTL865X_MODEL_KERNEL)
/* memDump() has defined in rtl_utils.c. */
#else
void memDump(void *start, uint32 size, int8 * strHeader)
{

	int32     row, column, index, index2, max;
	uint8    *buf, ascii[17];
	char      empty = ' ';

	assert(start && (size > 0));
	buf = (uint8 *) start;

	/*
	   16 bytes per line
	 */
	if (strHeader)
		printf("%s", strHeader);
	column = size % 16;
	row = (size / 16) + 1;
	for (index = 0; index < row; index++, buf += 16)
	{
		memset(ascii, 0, 17);
		printf("\n%08x ", (memaddr) buf);

		max = (index == row - 1) ? column : 16;

		//Hex
		for (index2 = 0; index2 < max; index2++)
		{
			if (index2 == 8)
				printf("  ");
			printf("%02x ", (uint8) buf[index2]);
			ascii[index2] = ((uint8) buf[index2] < 32) ? empty : buf[index2];
		}

		if (max != 16)
		{
			if (max < 8)
				printf("  ");
			for (index2 = 16 - max; index2 > 0; index2--)
				printf("   ");
		}

		//ASCII
		printf("  %s", ascii);
	}
	printf("\nThe total length of this packet is: %i bytes.\n",size);
	return;
}
#endif /*0*/


/*	if buffer ptr* has field "checksum" ,need set to zero
	ptr:l3 ip header ptr , len:(measured in octets) ,resid: resid check sum
	return :host-endian checksum
*/
uint16 ipcsum(uint16 *ptr, uint32 len, uint16 resid) {
	uint32 csum = resid;
	uint32 odd = 0;
//	rtlglue_printf("***** the ptr is [%d]*****\n", *ptr);
//	rtlglue_printf("****  the len is [%d]****\n", len);
  //      rtlglue_printf("***** the resid is [%d]****\n", resid);
	if(len & 1) 
		odd = 1;

	len = len >> 1;
//	rtlglue_printf("**** the len is [%d]***\n", len);	
	for(;len > 0 ; len--,ptr++){ 
		csum += ntohs(*ptr);
//		rtlglue_printf("the *ptr is [%d]\n", *ptr);
//		rtlglue_printf("***** the csum is [%d]****\n", csum);
	}

	if(odd)
		csum += (*((uint8 *)ptr) <<8) & 0xff00;

	/* take care of 1's complement */
	while(csum >> 16)
		csum = (csum & 0xffff) + (csum >> 16);

//	if(csum == 0xffff)	csum = 0;

	return((uint16)csum);
}

uint16 ipadjcsum(uint16 old, uint32 diff) {
	uint32 csum = old + diff;

	csum = (csum & 0xffff) + (csum >> 16);
	if(!csum)	csum = 0xffff;
	return((uint16)csum);
}

#if 0
/* 
 * Check whether "cp" is a valid ascii representation
 * of an Internet address and convert to a binary address.
 * Returns 1 if the address is valid, 0 if not.
 * This replaces inet_addr, the return value from which
 * cannot distinguish between failure and a local broadcast address.
 * returns in network order
 */
int32 inet_aton(const int8 *cp, struct in_addr *addr){
	uint32 val;
	int32 base, n;
	int8 c;
	uint32 parts[4];
	uint32 *pp = parts;

	c = *cp;
	for (;;) {
		/*
		 * Collect number up to ``.''.
		 * Values are specified as for C:
		 * 0x=hex, 0=octal, isdigit=decimal.
		 */
		if (!isdigit(c))
			return (0);
		val = 0; base = 10;

		//determine the base
		if (c == '0') {
			c = *++cp;
			if (c == 'x' || c == 'X')
				base = 16, c = *++cp;
			else
				base = 8;
		}

		for (;;) {
			if (isascii(c) && isdigit(c)) {
				val = (val * base) + (c - '0');
				c = *++cp;
			} else if (base == 16 && isascii(c) && isxdigit(c)) {
				val = (val << 4) |
					(c + 10 - (islower(c) ? 'a' : 'A'));
				c = *++cp;
			} else
				break;
		}

		if (c == '.') {
			/*
			 * Internet format:
			 *	a.b.c.d
			 *	a.b.c	(with c treated as 16 bits)
			 *	a.b	(with b treated as 24 bits)
			 */
			if (pp >= parts + 3)
				return (0);
			*pp++ = val;
			c = *++cp;
		} else
			break;
	}
	/*
	 * Check for trailing characters.
	 */
	if (c != '\0' && (!isascii(c) || !isspace(c)))
		return (0);
	/*
	 * Concoct the address according to
	 * the number of parts specified.
	 */
	n = pp - parts + 1;
	switch (n) {

	case 0:
		return (0);		/* initial nondigit */

	case 1:				/* a -- 32 bits */
		break;

	case 2:				/* a.b -- 8.24 bits */
		if ((val > 0xffffff) || (parts[0] > 0xff))
			return (0);
		val |= parts[0] << 24;
		break;

	case 3:				/* a.b.c -- 8.8.16 bits */
		if ((val > 0xffff) || (parts[0] > 0xff) || (parts[1] > 0xff))
			return (0);
		val |= (parts[0] << 24) | (parts[1] << 16);
		break;

	case 4:				/* a.b.c.d -- 8.8.8.8 bits */
		if ((val > 0xff) || (parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff))
			return (0);
		val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
		break;
	}
	if (addr)
		addr->s_addr = htonl(val);
	return (1);
}
#endif /*0*/

#ifdef __KERNEL__
typedef uint32 in_addr_t;
 int inet_aton(const char *cp, struct in_addr *addrptr)
{
	in_addr_t addr;
	int value;
	int part;

	addr = 0;
	for (part = 1; part <= 4; part++) {

		if (!isdigit(*cp))
			return 0;

		value = 0;
		while (isdigit(*cp)) {
			value *= 10;
			value += *cp++ - '0';
			if (value > 255)
				return 0;
		}

		if (part < 4) {
			if (*cp++ != '.')
				return 0;
		} else {
			char c = *cp++;
			if (c != '\0' && !isspace(c))
			return 0;
		}

		addr <<= 8;
		addr |= value;
	}

	/*  W. Richard Stevens in his book UNIX Network Programming,
	 *  Volume 1, second edition, on page 71 says:
	 *
	 *  An undocumented feature of inet_aton is that if addrptr is
	 *  a null pointer, the function still performs it validation
	 *  of the input string, but does not store the result.
	 */
	if (addrptr) {
	    addrptr->s_addr = htonl(addr);
	}

	return 1;
}
#endif

/*deprecated.*/
uint32 inet_addr(const int8 *cp){

	struct in_addr a;

	if (!inet_aton(cp, &a))
		return -1;
	else
		return a.s_addr;
}
static int8 *ui8tod( uint8 n, int8 *p )
{
	if( n > 99 ) *p++ = (n/100) + '0';
	if( n >  9 ) *p++ = ((n/10)%10) + '0';
	*p++ = (n%10) + '0';
	return p;
}

int8 *inet_ntoa(struct in_addr ina)
{
	static int8 buf[4*sizeof "123"];
	int8 *p = buf;
	uint8 *ucp = (unsigned char *)&ina;

	p = ui8tod( ucp[0] & 0xFF, p);
	*p++ = '.';
	p = ui8tod( ucp[1] & 0xFF, p);
	*p++ = '.';
	p = ui8tod( ucp[2] & 0xFF, p);
	*p++ = '.';
	p = ui8tod( ucp[3] & 0xFF, p);
	*p++ = '\0';

	return (buf);
}



/*
 * Convert an ASCII representation of an ethernet address to
 * binary form.
 * Original Author: hiwu
 */
struct ether_addr * ether_aton (const int8 *a)
{
  int32 i;
  static struct ether_addr o;
  int32 o0, o1, o2, o3, o4, o5;

  i = sscanf (a, "%02x-%02x-%02x-%02x-%02x-%02x", &o0, &o1, &o2, &o3, &o4, &o5);

  if (i != 6)
    return (NULL);

  o.octet[0] = o0;
  o.octet[1] = o1;
  o.octet[2] = o2;
  o.octet[3] = o3;
  o.octet[4] = o4;
  o.octet[5] = o5;

  return ((struct ether_addr *) &o);
}

/*
 * Convert a binary representation of an ethernet address to
 * an ASCII string.
 * Original Author: hiwu
 */
int8 * ether_ntoa (const struct ether_addr *n)
{
  int32 i;
  static int8 a[18];

  i = sprintf (a, "%02x-%02x-%02x-%02x-%02x-%02x", n->octet[0], n->octet[1], n->octet[2],
	       n->octet[3], n->octet[4], n->octet[5]);
  if (i < 11)
    return (NULL);
  return ((int8 *) & a);
}

/*
 * Convert HEX representation of a string to a binary form
 */

#if !defined(CONFIG_DEFAULTS_KERNEL_3_18)
int8 * hex2bin (const int8 *a)
{
	static int8	buffer[2048]={0};
	uint32	i;
	int32	o;

	for(i=0;i<strlen(a);i+=2)
	{
		sscanf(a+i,"%02x",&o);
		buffer[i/2] = o;
	}

	return (buffer);
}
#endif

void set_mac (int8 *a, int8 h1, int8 h2, int8 h3, int8 h4, int8 h5, int8 h6)
{
	int8 *b = a;

	*b++ = h1;
	*b++ = h2;
	*b++ = h3;
	*b++ = h4;
	*b++ = h5;
	*b = h6;
}

void set_v6addr (int8 *a, int8 h1, int8 h2, int8 h3, int8 h4, int8 h5, int8 h6, int8 h7, int8 h8, int8 h9, int8 h10,int8 h11,int8 h12, int8 h13,int8 h14,int8 h15, int8 h16)
{
	int8 *b = a;
	*b++ = h1;
	*b++ = h2;
	*b++ = h3;
	*b++ = h4;
	*b++ = h5;
	*b++ = h6;
	*b++ = h7;
	*b++ = h8;
	*b++ = h9;
	*b++ = h10;
	*b++ = h11;
	*b++ = h12;
	*b++ = h13;
	*b++ = h14;
	*b++ = h15;
	*b = h16;
}