original files of m241
This commit is contained in:
@@ -0,0 +1,475 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
* INTERPEAK SOURCE FILE
|
||||
*
|
||||
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipcom_checksum.c,v $ $Revision: 1.28.10.3 $
|
||||
* $Source: /home/interpeak/CVSRoot/ipcom/port/src/ipcom_checksum.c,v $
|
||||
* $Author: hxie $
|
||||
* $State: Exp $ $Locker: $
|
||||
*
|
||||
* INTERPEAK_COPYRIGHT_STRING
|
||||
* Design and implementation by Kenneth Jonsson <kenneth@interpeak.se>
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 1 DESCRIPTION
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 2 CONFIGURATION
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#include "ipcom_config.h"
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 3 INCLUDE FILES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#define IPCOM_USE_CLIB_PROTO
|
||||
#include "ipcom_clib.h"
|
||||
#include "ipcom_inet.h"
|
||||
#include "ipcom_sock.h"
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 4 DEFINES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* IPCOM_CPY_32_BITS_ALIGNED
|
||||
*===========================================================================
|
||||
* Description: Copies 32-bits of data where the source and destination
|
||||
* addresses both are aligned on a 32-bit boundary.
|
||||
*
|
||||
*/
|
||||
#define IPCOM_CPY_32_BITS_ALIGNED \
|
||||
data = *dst_u32++ = *src_u32++; \
|
||||
chksum += (Ip_u16) data + (data >> 16); \
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* IPCOM_CPY_32_BITS_UNALIGNED
|
||||
*===========================================================================
|
||||
* Description: Copies 32-bits of data where the source and destination
|
||||
* addresses cannot be aligned on a 32-bit boundary at the same
|
||||
* time. Data is read and written in 32-bit chunks at a 32-bit
|
||||
* boundary.
|
||||
*
|
||||
*/
|
||||
#ifdef IP_BIG_ENDIAN
|
||||
#define IPCOM_CPY_32_BITS_UNALIGNED(shift1, shift2) \
|
||||
data = src_data << shift1; \
|
||||
src_data = *src_u32++; \
|
||||
data = (src_data >> shift2) | data; \
|
||||
chksum += (Ip_u16) data; \
|
||||
*dst_u32++ = data; \
|
||||
chksum += (data >> 16);
|
||||
#else /* IP_LITTLE_ENDIAN */
|
||||
#define IPCOM_CPY_32_BITS_UNALIGNED(shift1, shift2) \
|
||||
data = src_data >> shift1; \
|
||||
src_data = *src_u32++; \
|
||||
data = (src_data << shift2) | data; \
|
||||
chksum += (Ip_u16) data; \
|
||||
*dst_u32++ = data; \
|
||||
chksum += (data >> 16);
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* IPCOM_UNALIGNED_CPY_LOOP
|
||||
*===========================================================================
|
||||
* Description: Copies data as long as a full 32-bit word can be written.
|
||||
*
|
||||
*/
|
||||
#define IPCOM_UNALIGNED_CPY_LOOP(shift1, shift2) \
|
||||
i = (int)((len - octet_unalignment) >> 5); \
|
||||
while (i--) \
|
||||
{ \
|
||||
IPCOM_CPY_32_BITS_UNALIGNED(shift1, shift2); \
|
||||
IPCOM_CPY_32_BITS_UNALIGNED(shift1, shift2); \
|
||||
IPCOM_CPY_32_BITS_UNALIGNED(shift1, shift2); \
|
||||
IPCOM_CPY_32_BITS_UNALIGNED(shift1, shift2); \
|
||||
IPCOM_CPY_32_BITS_UNALIGNED(shift1, shift2); \
|
||||
IPCOM_CPY_32_BITS_UNALIGNED(shift1, shift2); \
|
||||
IPCOM_CPY_32_BITS_UNALIGNED(shift1, shift2); \
|
||||
IPCOM_CPY_32_BITS_UNALIGNED(shift1, shift2); \
|
||||
} \
|
||||
i = (int)(((len - octet_unalignment) & 0x1f) >> 2); \
|
||||
while (i--) \
|
||||
{ \
|
||||
IPCOM_CPY_32_BITS_UNALIGNED(shift1, shift2); \
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 5 TYPES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 6 EXTERN PROTOTYPES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#ifdef IPCOM_USE_ASM
|
||||
IP_PUBLIC Ip_u32
|
||||
ipcom_in_checksum_update2_asm(void *pbuf, Ip_size_t bytes);
|
||||
IP_PUBLIC Ip_u32
|
||||
ipcom_in_checksum_memcpy_asm(void *dst, void *src, Ip_size_t bytes);
|
||||
#endif
|
||||
|
||||
#ifdef IP_PORT_LKM
|
||||
IP_EXTERN Ip_u32
|
||||
ipcom_in_checksum_update2(void *pbuf, Ip_size_t bytes);
|
||||
#endif
|
||||
/*
|
||||
****************************************************************************
|
||||
* 7 LOCAL PROTOTYPES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 8 DATA
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 9 STATIC FUNCTIONS
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 10 GLOBAL FUNCTIONS
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 11 PUBLIC FUNCTIONS
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipcom_in_checksum_update
|
||||
*===========================================================================
|
||||
* Description: Computes the internet checksum (RFC 1071). NOTE
|
||||
* it does not compute the 1 complement checksum.
|
||||
* Parameters: pbuf and bytes.
|
||||
* Returns: A standard internet checksum..
|
||||
*
|
||||
*/
|
||||
IP_PUBLIC Ip_u32
|
||||
ipcom_in_checksum_update(void *pbuf, Ip_size_t bytes)
|
||||
{
|
||||
Ip_u32 sum;
|
||||
#if defined(IP_PORT_LKM) && !defined(IP_TARGET_ARM) && !defined(IP_TARGET_MIPS)
|
||||
sum = ipcom_in_checksum_update2(pbuf, bytes);
|
||||
/* One folding step MUST be done to avoid overflow in IPNET/IPLITE */
|
||||
return (sum & 0xffff) + (sum >> 16);
|
||||
#else
|
||||
Ip_u32 nwords;
|
||||
Ip_u16 *buf;
|
||||
#ifdef IPCOM_USE_ASM
|
||||
if (IP_LIKELY(((long)pbuf & 0x1) == 0)
|
||||
&& IP_LIKELY(bytes >= sizeof(Ip_u16)))
|
||||
{
|
||||
sum = ipcom_in_checksum_update2_asm(pbuf, bytes);
|
||||
/* One folding step MUST be done to avoid overflow in IPNET/IPLITE */
|
||||
return (sum & 0xffff) + (sum >> 16);
|
||||
}
|
||||
#endif
|
||||
buf = (Ip_u16 *) pbuf;
|
||||
sum = 0;
|
||||
|
||||
for (nwords = (Ip_u32)bytes >> 5; nwords > 0; nwords--)
|
||||
{
|
||||
sum += *buf++; sum += *buf++; sum += *buf++; sum += *buf++;
|
||||
sum += *buf++; sum += *buf++; sum += *buf++; sum += *buf++;
|
||||
sum += *buf++; sum += *buf++; sum += *buf++; sum += *buf++;
|
||||
sum += *buf++; sum += *buf++; sum += *buf++; sum += *buf++;
|
||||
}
|
||||
for (nwords = (Ip_u32)(bytes & 0x1f) >> 1; nwords > 0; nwords--)
|
||||
sum += *buf++;
|
||||
|
||||
/* Add left-over byte, if any. */
|
||||
if (bytes & 0x01)
|
||||
sum += *buf & ip_htons(0xff00);
|
||||
|
||||
return sum;
|
||||
#endif /* IP_PORT_LKM && !IP_TARGET_ARM*/
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipcom_in_checksum_finish
|
||||
*===========================================================================
|
||||
* Description: Computes the one complement internet checksum (RFC 1071).
|
||||
* Parameters: sum - The accumulated 32 bit internet sum.
|
||||
* Returns: A one complement standard internet checksum.
|
||||
*
|
||||
*/
|
||||
IP_PUBLIC Ip_u16
|
||||
ipcom_in_checksum_finish(Ip_u32 sum)
|
||||
{
|
||||
/* Fold 32-bit sum to 16 bits. */
|
||||
while (sum >> 16)
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
|
||||
return (Ip_u16)~(Ip_u16)sum;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipcom_in_checksum
|
||||
*===========================================================================
|
||||
* Description: Calculates the checksum on the IPv4 header.
|
||||
* Parameters:
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_PUBLIC Ip_u16
|
||||
ipcom_in_checksum(void *buf, Ip_size_t bytes)
|
||||
{
|
||||
Ip_u32 sum;
|
||||
|
||||
sum = ipcom_in_checksum_update(buf, bytes);
|
||||
|
||||
/* inline ipcom_in_checksum_finish code: */
|
||||
while (sum >> 16)
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
|
||||
return (Ip_u16)~(Ip_u16)sum;
|
||||
}
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipcom_in_checksum_update_pkt
|
||||
*===========================================================================
|
||||
* Description: Calculates the checksum on the IPv4 header.
|
||||
* Parameters:
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_PUBLIC Ip_u32
|
||||
ipcom_in_checksum_update_pkt(Ipcom_pkt *pkt, Ip_u32 chksum)
|
||||
{
|
||||
Ip_u32 sum = chksum;
|
||||
Ip_u32 pkt_sum = 0;
|
||||
int len = 0;
|
||||
while (pkt != IP_NULL)
|
||||
{
|
||||
pkt_sum = ipcom_in_checksum_update(pkt->data+pkt->start, pkt->end-pkt->start);
|
||||
if (len & 0x01)
|
||||
pkt_sum = (pkt_sum >> 8) + ((pkt_sum & 0xff) << 8);
|
||||
sum += pkt_sum;
|
||||
len += (pkt->end - pkt->start);
|
||||
pkt = pkt->next_part;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipcom_in_checksum_pkt
|
||||
*===========================================================================
|
||||
* Description: Calculates the checksum on the IPv4 header.
|
||||
* Parameters:
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_PUBLIC Ip_u16
|
||||
ipcom_in_checksum_pkt(Ipcom_pkt *pkt, Ip_u32 chksum)
|
||||
{
|
||||
Ip_u32 sum = ipcom_in_checksum_update_pkt(pkt, chksum);
|
||||
return ipcom_in_checksum_finish(sum);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipcom_in_checksum_memcpy
|
||||
*===========================================================================
|
||||
* Description: Copies data and calculate the internet checksum at the same
|
||||
* time.
|
||||
* Parameters: dst - Destination buffer.
|
||||
* src - Source buffer.
|
||||
* len - Number of octets to copy.
|
||||
* Returns: The intermediate internet checksum, use
|
||||
* ipcom_in_checksum_finish() to get the actual checksum.
|
||||
*
|
||||
*/
|
||||
#if !defined(IP_PORT_LKM) || (defined(IP_PORT_LKM) && (defined(IP_TARGET_ARM) || defined(IP_TARGET_MIPS)))
|
||||
IP_PUBLIC Ip_u32
|
||||
ipcom_in_checksum_memcpy(void *dst, void *src, Ip_size_t len)
|
||||
{
|
||||
#ifdef IPCOM_USE_ASM
|
||||
Ip_u32 sum = ipcom_in_checksum_memcpy_asm(dst, src, len);
|
||||
/* One folding step MUST be done to avoid overflow in IPNET/IPLITE */
|
||||
return (sum & 0xffff) + (sum >> 16);
|
||||
#elif defined(IPBOUNDS) || defined(__BOUNDS_CHECKING_ON) || defined(IP_PORT_LKM)
|
||||
(void)ipcom_copy_from_user(dst, src, len);
|
||||
return ipcom_in_checksum_update(dst, len);
|
||||
#else
|
||||
Ip_u8 *dst_u8;
|
||||
Ip_u8 *src_u8;
|
||||
Ip_u32 *dst_u32;
|
||||
Ip_u32 *src_u32;
|
||||
Ip_u32 data;
|
||||
Ip_u32 src_data;
|
||||
Ip_u32 chksum = 0;
|
||||
int i;
|
||||
int initial_octets;
|
||||
int octet_unalignment = 0;
|
||||
Ip_bool dst_addr_is_odd = (Ip_bool)((Ip_ptrdiff_t) dst & 0x1);
|
||||
|
||||
initial_octets = (int) IP_MIN(((-(Ip_ptrdiff_t) dst) & 0x3), (Ip_ptrdiff_t) len);
|
||||
if (initial_octets == 0)
|
||||
{
|
||||
dst_u32 = (Ip_u32 *) dst;
|
||||
src_u32 = (Ip_u32 *) src;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst_u8 = (Ip_u8 *) dst;
|
||||
src_u8 = (Ip_u8 *) src;
|
||||
for (i = 0; i < initial_octets; ++i)
|
||||
{
|
||||
/* Copy initial octets (so that dst will be 32-bit aligned) */
|
||||
data = *dst_u8++ = *src_u8++;
|
||||
#ifdef IP_BIG_ENDIAN
|
||||
if ((i ^ dst_addr_is_odd) & 0x1)
|
||||
chksum += data;
|
||||
else
|
||||
chksum += data << 8;
|
||||
#else /* IP_LITTLE_ENDIAN */
|
||||
if ((i ^ dst_addr_is_odd) & 0x1)
|
||||
chksum += data << 8;
|
||||
else
|
||||
chksum += data;
|
||||
#endif
|
||||
}
|
||||
dst_u32 = (Ip_u32 *) dst_u8;
|
||||
src_u32 = (Ip_u32 *) src_u8;
|
||||
len -= initial_octets;
|
||||
}
|
||||
/* dst is now 32-bit aligned */
|
||||
|
||||
if (((Ip_ptrdiff_t) dst_u32 & 0x3) == ((Ip_ptrdiff_t) src_u32 & 0x3))
|
||||
{
|
||||
/* Both src and dst is now on an even 32-bit boundary */
|
||||
i = (int)(len >> 5);
|
||||
while (i--)
|
||||
{
|
||||
/* Big main copy loop */
|
||||
IPCOM_CPY_32_BITS_ALIGNED;
|
||||
IPCOM_CPY_32_BITS_ALIGNED;
|
||||
IPCOM_CPY_32_BITS_ALIGNED;
|
||||
IPCOM_CPY_32_BITS_ALIGNED;
|
||||
IPCOM_CPY_32_BITS_ALIGNED;
|
||||
IPCOM_CPY_32_BITS_ALIGNED;
|
||||
IPCOM_CPY_32_BITS_ALIGNED;
|
||||
IPCOM_CPY_32_BITS_ALIGNED;
|
||||
}
|
||||
|
||||
i = (int)((len & 0x1f) >> 2);
|
||||
while (i--)
|
||||
{
|
||||
/* Small main copy loop */
|
||||
IPCOM_CPY_32_BITS_ALIGNED;
|
||||
}
|
||||
|
||||
len -= len & ~0x3;
|
||||
}
|
||||
else if (len >= 4)
|
||||
{
|
||||
/* dst and src cannot be aligned */
|
||||
octet_unalignment = (int)((Ip_ptrdiff_t) src_u32 & 0x3);
|
||||
src_u32 = (Ip_u32 *) ((Ip_u8 *) src_u32 - octet_unalignment);
|
||||
src_data = *src_u32++;
|
||||
/* src is now 32-bit aligned */
|
||||
|
||||
switch (octet_unalignment)
|
||||
{
|
||||
case 1:
|
||||
IPCOM_UNALIGNED_CPY_LOOP(8, 24);
|
||||
break;
|
||||
case 2:
|
||||
IPCOM_UNALIGNED_CPY_LOOP(16, 16);
|
||||
break;
|
||||
case 3:
|
||||
IPCOM_UNALIGNED_CPY_LOOP(24, 8);
|
||||
break;
|
||||
default:
|
||||
IP_PANIC();
|
||||
break;
|
||||
}
|
||||
--src_u32;
|
||||
len -= ((len - octet_unalignment) & ~0x3);
|
||||
}
|
||||
|
||||
if (len)
|
||||
{
|
||||
/* Copy data that cannot be written in 32-bit chunks */
|
||||
src_u8 = (Ip_u8 *) src_u32 + octet_unalignment;
|
||||
dst_u8 = (Ip_u8 *) dst_u32;
|
||||
for (i = 0; i < (int) len; ++i)
|
||||
{
|
||||
data = *dst_u8++ = *src_u8++;
|
||||
#ifdef IP_BIG_ENDIAN
|
||||
if (i & 0x1)
|
||||
chksum += data;
|
||||
else
|
||||
chksum += data << 8;
|
||||
#else /* IP_LITTLE_ENDIAN */
|
||||
if (i & 0x1)
|
||||
chksum += data << 8;
|
||||
else
|
||||
chksum += data;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (dst_addr_is_odd)
|
||||
{
|
||||
/* The checksum has the low and hi bytes swaped */
|
||||
return (((Ip_u8 *) &chksum)[0] << 8)
|
||||
+ ((Ip_u8 *) &chksum)[1]
|
||||
+ (((Ip_u8 *) &chksum)[2] << 8)
|
||||
+ ((Ip_u8 *) &chksum)[3]; /*lint !e647 */
|
||||
}
|
||||
|
||||
return chksum;
|
||||
#endif /* IPCOM_USE_ASM */
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* END OF FILE
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user