/*
*********************************************************************************************************
*                                              uC/TCP-IP
*                                      The Embedded TCP/IP Suite
*
*                          (c) Copyright 2003-2007; Micrium, Inc.; Weston, FL
*
*               All rights reserved.  Protected by international copyright laws.
*
*               uC/TCP-IP is provided in source form for FREE evaluation, for educational
*               use or peaceful research.  If you plan on using uC/TCP-IP in a commercial
*               product you need to contact Micrium to properly license its use in your
*               product.  We provide ALL the source code for your convenience and to help
*               you experience uC/TCP-IP.  The fact that the source code is provided does
*               NOT mean that you can use it without paying a licensing fee.
*
*               Knowledge of the source code may NOT be used to develop a similar product.
*
*               Please help us continue to provide the Embedded community with the finest
*               software available.  Your honesty is greatly appreciated.
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*
*                                       NETWORK UTILITY LIBRARY
*
* Filename      : net_util.c
* Version       : V1.89
* Programmer(s) : ITJ
*********************************************************************************************************
* Note(s)       : (1) NO compiler-supplied standard library functions are used by the network protocol suite.
*                     'net_util.*' implements ALL network-specific library functions.
*
*                     See also 'net.h  NETWORK INCLUDE FILES  Note #3'.
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*                                            INCLUDE FILES
*********************************************************************************************************
*/

#define    NET_UTIL_MODULE
#include  <net.h>


/*$PAGE*/
/*
*********************************************************************************************************
*                                            LOCAL DEFINES
*********************************************************************************************************
*/

#define  NET_UTIL_16_BIT_ONES_CPL_NEG_ZERO            0xFFFF


#define  NET_UTIL_16_BIT_SUM_ERR_NONE             DEF_BIT_NONE
#define  NET_UTIL_16_BIT_SUM_ERR_NULL_SIZE        DEF_BIT_01
#define  NET_UTIL_16_BIT_SUM_ERR_LAST_OCTET       DEF_BIT_02


/*
*********************************************************************************************************
*                                           LOCAL CONSTANTS
*********************************************************************************************************
*/


/*
*********************************************************************************************************
*                                          LOCAL DATA TYPES
*********************************************************************************************************
*/


/*
*********************************************************************************************************
*                                            LOCAL TABLES
*********************************************************************************************************
*/


/*
*********************************************************************************************************
*                                       LOCAL GLOBAL VARIABLES
*********************************************************************************************************
*/


/*$PAGE*/
/*
*********************************************************************************************************
*                                      LOCAL FUNCTION PROTOTYPES
*********************************************************************************************************
*/

static  CPU_INT32U  NetUtil_16BitSumHdrCalc        (void         *phdr,
                                                    CPU_INT16U    hdr_size);

static  CPU_INT32U  NetUtil_16BitSumDataCalc       (void         *p_data,
                                                    CPU_INT16U    data_size,
                                                    CPU_INT08U   *poctet_prev,
                                                    CPU_INT08U   *poctet_last,
                                                    CPU_BOOLEAN   prev_octet_valid,
                                                    CPU_BOOLEAN   last_pkt_buf,
                                                    CPU_INT08U   *psum_err);

static  CPU_INT16U  NetUtil_16BitOnesCplSumDataCalc(void         *pdata_buf,
                                                    void         *ppseudo_hdr,
                                                    CPU_INT16U    pseudo_hdr_size,
                                                    NET_ERR      *perr);

/*
*********************************************************************************************************
*                                     LOCAL CONFIGURATION ERRORS
*********************************************************************************************************
*/


/*$PAGE*/
/*
*********************************************************************************************************
*                                 NetUtil_16BitOnesCplChkSumHdrCalc()
*
* Description : Calculate 16-bit one's-complement check-sum on packet header.
*
*               (1) See RFC #1071, Sections 1, 2.(1), & 4.1 for summary of 16-bit one's-complement
*                   check-sum & algorithm.
*
*               (2) To correctly calculate 16-bit one's-complement check-sums on memory buffers of any 
*                   octet-length & word-alignment, the check-sums MUST be calculated in network-order
*                   on headers that are arranged in network-order (see also 'NetUtil_16BitSumHdrCalc()
*                   Note #5b').
*
*
* Argument(s) : phdr        Pointer to packet header.
*
*               hdr_size    Size    of packet header.
*
*               perr        Pointer to variable that will receive the return error code from this function :
*
*                               NET_UTIL_ERR_NONE           Check-sum calculated; check return value.
*                               NET_UTIL_ERR_NULL_PTR       Argument 'phdr'     passed a NULL pointer.
*                               NET_UTIL_ERR_NULL_SIZE      Argument 'hdr_size' passed a zero size.
*
* Return(s)   : 16-bit one's-complement check-sum, if NO errors.
*
*               0,                                 otherwise.
*
* Caller(s)   : various.
*
*               This function is an INTERNAL network protocol suite function & SHOULD NOT be called by 
*               application function(s).
*
* Note(s)     : (3) (a) Since the 16-bit sum calculation is returned as a 32-bit network-order value 
*                       (see 'NetUtil_16BitSumHdrCalc()  Note #5c1'), ...
*
*                   (b) ... the final check-sum MUST be converted to host-order but MUST NOT be re-
*                       converted back to network-order (see 'NetUtil_16BitSumHdrCalc()  Note #5c3').
*********************************************************************************************************
*/

NET_CHK_SUM  NetUtil_16BitOnesCplChkSumHdrCalc (void        *phdr,
                                                CPU_INT16U   hdr_size,
                                                NET_ERR     *perr)
{
    CPU_INT32U   sum;
    NET_CHK_SUM  chk_sum;
    NET_CHK_SUM  chk_sum_host;


#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
                                                                /* ------------------ VALIDATE PTR -------------------- */
    if (phdr == (void *)0) {
       *perr =  NET_UTIL_ERR_NULL_PTR;
        return (0);
    }
                                                                /* ------------------ VALIDATE SIZE ------------------- */
    if (hdr_size < 1) {
       *perr =  NET_UTIL_ERR_NULL_SIZE;
        return (0);
    }
#endif

                                                                /* --------- CALC HDR'S 16-BIT ONE'S-CPL SUM ---------- */
    sum = NetUtil_16BitSumHdrCalc(phdr, hdr_size);              /* Calc  16-bit sum (see Note #3a).                     */

    while (sum >> 16) {                                         /* While 16-bit sum ovf's, ...                          */
        sum = (sum & 0x0000FFFF) + (sum >> 16);                 /* ... sum ovf bits back into 16-bit one's-cpl sum.     */
    }


    chk_sum      = ~((NET_CHK_SUM)sum);                         /* Perform one's cpl on one's-cpl sum.                  */
    chk_sum_host = NET_UTIL_NET_TO_HOST_16(chk_sum);            /* Conv back to host-order (see Note #3b).              */

   *perr         = NET_UTIL_ERR_NONE;

    return (chk_sum_host);                                      /* Rtn 16-bit chk sum (see Note #3).                    */
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                 NetUtil_16BitOnesCplChkSumHdrVerify()
*
* Description : (1) Verify 16-bit one's-complement check-sum on packet header :
*
*                   (a) Calculate one's-complement sum on packet header
*                   (b) Verify check-sum by comparison of one's-complement sum to one's-complement 
*                         '-0' value (negative zero)
*
*               (2) See RFC #1071, Sections 1, 2.(1), & 4.1 for summary of 16-bit one's-complement
*                   check-sum & algorithm.
*
*               (3) To correctly calculate 16-bit one's-complement check-sums on memory buffers of any 
*                   octet-length & word-alignment, the check-sums MUST be calculated in network-order
*                   on headers that are arranged in network-order (see also 'NetUtil_16BitSumHdrCalc()
*                   Note #5b').
*
*
* Argument(s) : phdr        Pointer to packet header.
*
*               hdr_size    Size    of packet header.
*
*               perr        Pointer to variable that will receive the return error code from this function :
*
*                               NET_UTIL_ERR_NONE           Check-sum verified; check return value.
*                               NET_UTIL_ERR_NULL_PTR       Argument 'phdr'     passed a NULL pointer.
*                               NET_UTIL_ERR_NULL_SIZE      Argument 'hdr_size' passed a zero size.
*
* Return(s)   : DEF_OK,   if valid check-sum.
*
*               DEF_FAIL, otherwise.
*
* Caller(s)   : various.
*
*               This function is an INTERNAL network protocol suite function & SHOULD NOT be called by 
*               application function(s).
*
* Note(s)     : (4) (a) Since the 16-bit sum calculation is returned as a 32-bit network-order value 
*                       (see 'NetUtil_16BitSumHdrCalc()  Note #5c1'), ...
*
*                   (b) ... the check-sum MUST be converted to host-order but MUST NOT be re-converted
*                       back to network-order for the final check-sum comparison
*                       (see 'NetUtil_16BitSumHdrCalc()  Note #5c3').
*********************************************************************************************************
*/

CPU_BOOLEAN  NetUtil_16BitOnesCplChkSumHdrVerify (void        *phdr,
                                                  CPU_INT16U   hdr_size,
                                                  NET_ERR     *perr)
{
    CPU_INT32U   sum;
    NET_CHK_SUM  chk_sum;
    NET_CHK_SUM  chk_sum_host;
    CPU_BOOLEAN  valid;


#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
                                                                /* ------------------ VALIDATE PTR -------------------- */
    if (phdr == (void *)0) {
       *perr =  NET_UTIL_ERR_NULL_PTR;
        return (DEF_FAIL);
    }
                                                                /* ------------------ VALIDATE SIZE ------------------- */
    if (hdr_size < 1) {
       *perr =  NET_UTIL_ERR_NULL_SIZE;
        return (DEF_FAIL);
    }
#endif

                                                                /* -------- VERIFY HDR'S 16-BIT ONE'S-CPL SUM --------- */
    sum = NetUtil_16BitSumHdrCalc(phdr, hdr_size);              /* Calc 16-bit sum (see Note #4a).                      */

    while (sum >> 16) {                                         /* While 16-bit sum ovf's, ...                          */
        sum = (sum & 0x0000FFFF) + (sum >> 16);                 /* ... sum ovf bits back into 16-bit one's-cpl sum.     */
    }

    chk_sum      = (NET_CHK_SUM)sum;
    chk_sum_host =  NET_UTIL_NET_TO_HOST_16(chk_sum);           /* Conv back to host-order (see Note #4b).              */

                                                                /* Verify chk sum (see Note #1b).                       */
    valid        = (chk_sum_host == NET_UTIL_16_BIT_ONES_CPL_NEG_ZERO) ? DEF_OK : DEF_FAIL;

   *perr         =  NET_UTIL_ERR_NONE;

    return (valid);
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                NetUtil_16BitOnesCplChkSumDataCalc()
*
* Description : Calculate 16-bit one's-complement check-sum on packet data.
*
*               (1) See RFC #1071, Sections 1, 2.(1), & 4.1 for summary of 16-bit one's-complement
*                   check-sum & algorithm.
*
*               (2) Check-sum calculated on packet data encapsulated in :
*
*                   (a) One or more network buffers             Support non-fragmented & fragmented packets
*                   (b) Transport layer pseudo-header           See RFC #768, Section 'Fields : Checksum' &
*                                                                   RFC #793, Section 3.1 'Header Format :
*                                                                       Checksum'.
*
*               (3) To correctly calculate 16-bit one's-complement check-sums on memory buffers of any 
*                   octet-length & word-alignment, the check-sums MUST be calculated in network-order on
*                   data & headers that are arranged in network-order (see also 'NetUtil_16BitSumDataCalc()
*                   Note #5b').
*
*
* Argument(s) : pdata_buf           Pointer to packet data network buffer(s) (see Note #2a).
*
*               ppseudo_hdr         Pointer to transport layer pseudo-header (see Note #2b).
*
*               pseudo_hdr_size     Size    of transport layer pseudo-header.
*
*               perr        Pointer to variable that will receive the return error code from this function :
*
*                               NET_UTIL_ERR_NONE               Check-sum calculated; check return value.
*
*                                                               - RETURNED BY NetUtil_16BitOnesCplSumDataCalc() : -
*                               NET_UTIL_ERR_NULL_PTR           Argument 'pdata_buf' passed a NULL pointer.
*                               NET_UTIL_ERR_NULL_SIZE          Packet data is a zero size.
*                               NET_UTIL_ERR_INVALID_PROTOCOL   Invalid data packet protocol.
*                               NET_BUF_ERR_INVALID_IX          Invalid buffer index.
*
* Return(s)   : 16-bit one's-complement check-sum, if NO errors.
*
*               0,                                 otherwise.
*
* Caller(s)   : various.
*
*               This function is an INTERNAL network protocol suite function & SHOULD NOT be called by 
*               application function(s).
*
* Note(s)     : (4) (a) Since the 16-bit one's-complement check-sum calculations are returned in host-
*                       order, ...
*
*                   (b) ... the returned check-sum MUST NOT be re-converted back to network-order.
*
*                   See also 'NetUtil_16BitSumDataCalc()         Note #5c3' &
*                            'NetUtil_16BitOnesCplSumDataCalc()  Note #4'.
*********************************************************************************************************
*/

NET_CHK_SUM  NetUtil_16BitOnesCplChkSumDataCalc (void        *pdata_buf,
                                                 void        *ppseudo_hdr,
                                                 CPU_INT16U   pseudo_hdr_size,
                                                 NET_ERR     *perr)
{
    CPU_INT16U   sum;
    NET_CHK_SUM  chk_sum;

                                                                /* Calc 16-bit one's-cpl sum (see Note #4a).            */
    sum = NetUtil_16BitOnesCplSumDataCalc(pdata_buf, ppseudo_hdr, pseudo_hdr_size, perr);
    if (*perr != NET_UTIL_ERR_NONE) {
         return (0);
    }

    chk_sum = ~((NET_CHK_SUM)sum);                              /* Perform one's cpl on one's-cpl sum.                  */

   *perr    = NET_UTIL_ERR_NONE;

    return (chk_sum);                                           /* Rtn 16-bit chk sum (see Note #4).                    */
}


/*$PAGE*/
/*
*********************************************************************************************************
*                               NetUtil_16BitOnesCplChkSumDataVerify()
*
* Description : (1) Verify 16-bit one's-complement check-sum on packet data :
*
*                   (a) Calculate one's-complement sum on packet data & packet pseudo-header
*                   (b) Verify check-sum by comparison of one's-complement sum to one's-complement 
*                         '-0' value (negative zero)
*
*               (2) See RFC #1071, Sections 1, 2.(1), & 4.1 for summary of 16-bit one's-complement
*                   check-sum & algorithm.
*
*               (3) Check-sum calculated on packet data encapsulated in :
*
*                   (a) One or more network buffers             Support non-fragmented & fragmented packets
*                   (b) Transport layer pseudo-header           See RFC #768, Section 'Fields : Checksum' &
*                                                                   RFC #793, Section 3.1 'Header Format :
*                                                                       Checksum'.
*
*               (4) To correctly calculate 16-bit one's-complement check-sums on memory buffers of any 
*                   octet-length & word-alignment, the check-sums MUST be calculated in network-order on
*                   data & headers that are arranged in network-order (see also 'NetUtil_16BitSumDataCalc()
*                   Note #5b').
*
*
* Argument(s) : pdata_buf           Pointer to packet data network buffer(s) (see Note #3a).
*
*               ppseudo_hdr         Pointer to transport layer pseudo-header (see Note #3b).
*
*               pseudo_hdr_size     Size    of transport layer pseudo-header.
*
*               perr        Pointer to variable that will receive the return error code from this function :
*
*                               NET_UTIL_ERR_NONE               Check-sum calculated; check return value.
*
*                                                               - RETURNED BY NetUtil_16BitOnesCplSumDataCalc() : -
*                               NET_UTIL_ERR_NULL_PTR           Argument 'pdata_buf' passed a NULL pointer.
*                               NET_UTIL_ERR_NULL_SIZE          Packet data is a zero size.
*                               NET_UTIL_ERR_INVALID_PROTOCOL   Invalid data packet protocol.
*                               NET_BUF_ERR_INVALID_IX          Invalid buffer index.
*
* Return(s)   : DEF_OK,   if valid check-sum.
*
*               DEF_FAIL, otherwise.
*
* Caller(s)   : various.
*
*               This function is an INTERNAL network protocol suite function & SHOULD NOT be called by 
*               application function(s).
*
* Note(s)     : (5) (a) Since the 16-bit one's-complement check-sum calculations are returned in host-
*                       order, ...
*
*                   (b) ... the returned check-sum MUST NOT be re-converted back to network-order for
*                       the final check-sum comparison.
*
*                   See also 'NetUtil_16BitSumDataCalc()         Note #5c3' &
*                            'NetUtil_16BitOnesCplSumDataCalc()  Note #4'.
*********************************************************************************************************
*/

CPU_BOOLEAN  NetUtil_16BitOnesCplChkSumDataVerify (void        *pdata_buf,
                                                   void        *ppseudo_hdr,
                                                   CPU_INT16U   pseudo_hdr_size,
                                                   NET_ERR     *perr)
{
    CPU_INT16U   sum;
    NET_CHK_SUM  chk_sum;
    CPU_BOOLEAN  valid;

                                                                /* Calc 16-bit one's-cpl sum (see Note #5a).            */
    sum = NetUtil_16BitOnesCplSumDataCalc(pdata_buf, ppseudo_hdr, pseudo_hdr_size, perr);
    if (*perr != NET_UTIL_ERR_NONE) {
         return (DEF_FAIL);
    }
                                                                /* Verify chk sum (see Notes #1b & #5b).                */
    chk_sum = (NET_CHK_SUM)sum;
    valid   = (chk_sum == NET_UTIL_16_BIT_ONES_CPL_NEG_ZERO) ? DEF_OK : DEF_FAIL;

   *perr    =  NET_UTIL_ERR_NONE;

    return (valid);
}


/*$PAGE*/
/*
*********************************************************************************************************
*********************************************************************************************************
*                                           LOCAL FUNCTIONS
*********************************************************************************************************
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*                                      NetUtil_16BitSumHdrCalc()
*
* Description : Calculate 16-bit sum on packet header memory buffer.
*
*               (1) Calculates the sum of consecutive 16-bit values.
*
*               (2) 16-bit sum is returned as a 32-bit value to preserve possible 16-bit summation overflow 
*                   in the upper 16-bits.
*
*
* Argument(s) : phdr        Pointer to packet header.
*               ----        Argument checked in NetUtil_16BitOnesCplChkSumHdrCalc(),
*                                               NetUtil_16BitOnesCplChkSumHdrVerify(),
*                                               NetUtil_16BitOnesCplSumDataCalc().
*
*               hdr_size    Size    of packet header.
*
* Return(s)   : 16-bit sum (see Note #2), if NO errors.
*
*               0,                        otherwise.
*
* Caller(s)   : NetUtil_16BitOnesCplChkSumHdrCalc(),
*               NetUtil_16BitOnesCplChkSumHdrVerify(),
*               NetUtil_16BitOnesCplSumDataCalc().
*
* Note(s)     : (3) Since many word-aligned processors REQUIRE that multi-octet words be located on word-
*                   aligned addresses, 16-bit sum calculation MUST ensure that 16-bit words are accessed
*                   on addresses that are multiples of 2 octets.
*
*                   If packet header memory buffer does NOT start on a 16-bit word address boundary, then 
*                   16-bit sum calculation MUST be performed by concatenating two consecutive 8-bit values.
*
*               (4) Modulo arithmetic is used to determine whether a memory buffer starts on the desired 
*                   word-aligned address boundary.
*
*                   Modulo arithmetic in ANSI-C REQUIREs operations performed on integer values.  Thus, 
*                   address values MUST be cast to an appropriately-sized integer value PRIOR to any
*                   modulo arithmetic operation.
*
*               (5) (a) Although "the sum of 16-bit integers can be computed in either byte order" 
*                       [RFC #1071, Section 2.(B)], the handling of odd-length &/or off-word-boundary 
*                       memory buffers is performed assuming network-order.
*
*                   (b) However, to correctly & consistently calculate 16-bit integer sums for even-/
*                       odd-length & word-/off-word-boundary memory buffers, the sums MUST be calculated 
*                       in network-order.
*
*                   (c) (1) To preserve possible 16-bit summation overflow (see Note #2) during all check-
*                           sum calculations, the 16-bit sum is returned as a 32-bit network-order value.
*
*                       (2) To encapsulate the network-order transform to the 16-bit check-sum calculations
*                           ONLY, the final check-sum MUST be converted to host-order.
*
*                           See 'NetUtil_16BitOnesCplChkSumHdrCalc()    Note #3b' &
*                               'NetUtil_16BitOnesCplChkSumHdrVerify()  Note #4b').
*
*                       (3) However, since network-to-host-order conversion & host-order memory access are
*                           inverse operations, the final host-order check-sum value MUST NOT be converted
*                           back to network-order for calculation or comparison.
*
*               (6) RFC #1071, Section 4.1 explicitly casts & sums the last odd-length octet in a check-sum 
*                   calculation as a 16-bit value.
*
*                   ???? However, this contradicts the following sections which state that "if the total
*                   length is odd, ... the last octet is padded on the right with ... one octet of zeros
*                   ... to form a 16 bit word for ... purposes ... [of] computing the checksum" :
*
*                   (a) RFC #768, Section     'Fields                     : Checksum'
*                   (b) RFC #792, Section     'Echo or Echo Reply Message : Checksum'
*                   (c) RFC #793, Section 3.1 'Header Format              : Checksum'
*
*                   See also 'NetUtil_16BitSumDataCalc()  Note #8'.
*********************************************************************************************************
*/
/*$PAGE*/
static  CPU_INT32U  NetUtil_16BitSumHdrCalc (void        *phdr,
                                             CPU_INT16U   hdr_size)
{
    CPU_INT32U   sum_32;
    CPU_INT32U   sum_val_32;
    CPU_INT16U   hdr_val_16;
    CPU_INT16U   size_rem;
    CPU_INT16U  *phdr_16;
    CPU_INT08U  *phdr_08;
    CPU_INT08U   modulo_16;

                                                                    /* ---------------- VALIDATE SIZE ----------------- */
    if (hdr_size < 1) {
        return (0);
    }


    size_rem  =  hdr_size;
    sum_32    =  0;

    modulo_16 = (CPU_INT08U)((CPU_ADDR)phdr % sizeof(CPU_INT16U));  /* See Note #4.                                     */
    if (modulo_16 == 0) {                                           /* If pkt hdr on 16-bit word boundary (see Note #3),*/
        phdr_16 = (CPU_INT16U *)phdr;
        while (size_rem >=  sizeof(CPU_INT16U)) {
            hdr_val_16   = (CPU_INT16U)*phdr_16++;
            sum_val_32   = (CPU_INT32U) NET_UTIL_HOST_TO_NET_16(hdr_val_16);    /* Conv to net-order (see Note #5b).    */
            sum_32      += (CPU_INT32U) sum_val_32;                 /* ... calc sum with 16-bit data words.             */
            size_rem    -=  sizeof(CPU_INT16U);
        }
        phdr_08 = (CPU_INT08U *)phdr_16;

    } else {                                                        /* Else if pkt hdr NOT on 16-bit word boundary, ... */
        phdr_08 = (CPU_INT08U *)phdr;
        while (size_rem >=  sizeof(CPU_INT16U)) {
            sum_val_32   = (CPU_INT32U)*phdr_08++;
            sum_val_32 <<=  DEF_OCTET_NBR_BITS;
            sum_val_32  += (CPU_INT32U)*phdr_08++;
            sum_32      += (CPU_INT32U) sum_val_32;                 /* ... calc sum with  8-bit data vals.              */
            size_rem    -=  sizeof(CPU_INT16U);
        }
    }

    if (size_rem > 0) {                                             /* Sum last octet, if any (see Note #6).            */
        sum_32 += (CPU_INT32U)*phdr_08;
    }


    return (sum_32);                                                /* Rtn 16-bit sum (see Note #5c1).                  */
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                     NetUtil_16BitSumDataCalc()
*
* Description : Calculate 16-bit sum on packet data memory buffer.
*
*               (1) Calculates the sum of consecutive 16-bit values.
*
*               (2) 16-bit sum is returned as a 32-bit value to preserve possible 16-bit summation overflow 
*                   in the upper 16-bits.
*
*
* Argument(s) : p_data              Pointer to packet data.
*               ------              Argument validated in NetUtil_16BitOnesCplSumDataCalc().
*
*               data_size           Size    of packet data (in this network buffer only
*                                                           [see 'NetUtil_16BitOnesCplSumDataCalc()  Note #1a']).
*
*               poctet_prev         Pointer to last octet from a fragmented packet's previous buffer.
*               -----------         Argument validated in NetUtil_16BitOnesCplSumDataCalc().
*
*               poctet_last         Pointer to variable that will receive the value of the last octet from a
*               -----------             fragmented packet's current buffer.
*
*                                   Argument validated in NetUtil_16BitOnesCplSumDataCalc().
*
*               prev_octet_valid    Indicate whether pointer to the last octet of the packet's previous
*               ----------------        buffer is valid.
*
*                                   Argument validated in NetUtil_16BitOnesCplSumDataCalc().
*
*               last_pkt_buf        Indicate whether the current packet buffer is the last packet buffer.
*               ------------        Argument validated in NetUtil_16BitOnesCplSumDataCalc().
*
*               psum_err            Pointer to variable that will receive the error return code(s) from this function :
*
*                                       NET_UTIL_16_BIT_SUM_ERR_NONE            No error return codes.
*
*                                   The following error return codes are bit-field codes logically OR'd & MUST 
*                                       be individually tested by bit-wise tests :
*
*                                       NET_UTIL_16_BIT_SUM_ERR_NULL_SIZE       Packet buffer's data size is
*                                                                                   a zero size.
*                                       NET_UTIL_16_BIT_SUM_ERR_LAST_OCTET      Last odd-length octet in packet 
*                                                                                   buffer is available; check
*                                                                                   'poctet_last' return value.
*
* Return(s)   : 16-bit sum (see Note #2), if NO errors.
*
*               0,                        otherwise.
*
* Caller(s)   : NetUtil_16BitOnesCplSumDataCalc().
*$PAGE*
* Note(s)     : (3) Since many word-aligned processors REQUIRE that multi-octet words be located on word-
*                   aligned addresses, 16-bit sum calculation MUST ensure that 16-bit words are accessed
*                   on addresses that are multiples of 2 octets.
*
*                   If packet data memory buffer does NOT start on a 16-bit word address boundary, then 
*                   16-bit sum calculation MUST be performed by concatenating two consecutive 8-bit values.
*
*               (4) Modulo arithmetic is used to determine whether a memory buffer starts on the desired 
*                   word-aligned address boundary.
*
*                   Modulo arithmetic in ANSI-C REQUIREs operations performed on integer values.  Thus, 
*                   address values MUST be cast to an appropriately-sized integer value PRIOR to any
*                   modulo arithmetic operation.
*
*               (5) (a) Although "the sum of 16-bit integers can be computed in either byte order" 
*                       [RFC #1071, Section 2.(B)], the handling of odd-length &/or off-word-boundary 
*                       memory buffers is performed assuming network-order.
*
*                   (b) However, to correctly & consistently calculate 16-bit integer sums for even-/
*                       odd-length & word-/off-word-boundary memory buffers, the sums MUST be calculated 
*                       in network-order so that the last octet of any packet buffer is correctly pre-
*                       pended to the first octet of the next packet buffer.
*
*                   (c) (1) To preserve possible 16-bit summation overflow (see Note #2) during all check-
*                           sum calculations, the 16-bit sum is returned as a 32-bit network-order value.
*
*                       (2) To encapsulate the network-order transform to the 16-bit check-sum calculations
*                           ONLY, the final check-sum MUST be converted to host-order
*                           (see 'NetUtil_16BitOnesCplSumDataCalc()  Note #4').
*
*                       (3) However, since network-to-host-order conversion & host-order memory access are
*                           inverse operations, the final host-order check-sum value MUST NOT be converted
*                           back to network-order for calculation or comparison.
*
*               (6) Optimized 32-bit sum calculations implemented in the network protocol suite's network-
*                   specific library port optimization file(s).
*
*                   See also 'net_util.h  FUNCTION PROTOTYPES  DEFINED IN PRODUCT'S  net_util_a.*  Note #1'.
*
*               (7) Since pointer arithmetic is based on the specific pointer data type & inherent pointer
*                   data type size, pointer arithmetic operands :
*
*                   (a) MUST be in terms of the specific pointer data type & data type size; ...
*                   (b) SHOULD NOT & in some cases MUST NOT be cast to other data types or data type sizes.
*
*               (8) The following sections state that "if the total length is odd, ... the last octet
*                   is padded on the right with ... one octet of zeros ... to form a 16 bit word for
*                   ... purposes ... [of] computing the checksum" :
*
*                   (a) RFC #768, Section     'Fields                     : Checksum'
*                   (b) RFC #792, Section     'Echo or Echo Reply Message : Checksum'
*                   (c) RFC #793, Section 3.1 'Header Format              : Checksum'
*
*                   See also 'NetUtil_16BitSumHdrCalc()  Note #6'.
*********************************************************************************************************
*/
/*$PAGE*/
static  CPU_INT32U  NetUtil_16BitSumDataCalc (void         *p_data,
                                              CPU_INT16U    data_size,
                                              CPU_INT08U   *poctet_prev,
                                              CPU_INT08U   *poctet_last,
                                              CPU_BOOLEAN   prev_octet_valid,
                                              CPU_BOOLEAN   last_pkt_buf,
                                              CPU_INT08U   *psum_err)
{
#if (NET_CFG_OPTIMIZE == NET_OPTIMIZE_SPD)
    CPU_INT08U    modulo_32;
#if ((defined(uC_CFG_OPTIMIZE_ASM_EN)) && \
             (uC_CFG_OPTIMIZE_ASM_EN   == DEF_ENABLED))
    CPU_INT16U    size_rem_32_offset;
    CPU_INT16U    size_rem_32;
#else
    CPU_INT32U    data_val_32;
    CPU_INT32U   *pdata_32;
#endif
#endif
    CPU_INT32U    sum_32;
    CPU_INT32U    sum_val_32;
    CPU_INT16U    data_val_16;
    CPU_INT16U    size_rem;
    CPU_INT16U   *pdata_16;
    CPU_INT08U   *pdata_08;
    CPU_INT08U    modulo_16;
    CPU_BOOLEAN   pkt_aligned_16;


    sum_32 = 0;


    if (data_size < 1) {                                        /* ------------ HANDLE NULL-SIZE DATA PKT ------------- */
       *psum_err = NET_UTIL_16_BIT_SUM_ERR_NULL_SIZE;

        if (prev_octet_valid != DEF_NO) {                       /* If null size & last octet from prev pkt buf avail .. */

            if (last_pkt_buf != DEF_NO) {                       /* ...   & on last pkt buf,              ...            */
                sum_val_32   = (CPU_INT32U)*poctet_prev;        /* ...   cast prev pkt buf's last octet, ...            */
                sum_val_32 <<=  DEF_OCTET_NBR_BITS;             /* ... pad odd-len pkt len (see Note #5) ...            */
                sum_32       =  sum_val_32;                     /* ...  & rtn prev pkt buf's last octet as last sum.    */

            } else {                                            /* ... & NOT on last pkt buf, ...                       */
               *poctet_last = *poctet_prev;                     /* ... rtn last octet from prev pkt buf as last octet.  */
                DEF_BIT_SET(*psum_err, NET_UTIL_16_BIT_SUM_ERR_LAST_OCTET);

            }

        } else {
            ;                                                   /* If null size & NO prev octet, NO action(s) req'd.    */
        }

        return (sum_32);                                        /* Rtn 16-bit sum (see Note #5c1).                      */
    }


/*$PAGE*/
                                                                    /* ----------- HANDLE NON-NULL DATA PKT ----------- */
    size_rem       =  data_size;
   *psum_err       =  NET_UTIL_16_BIT_SUM_ERR_NONE;

                                                                    /* See Notes #3 & #4.                               */
    modulo_16      = (CPU_INT08U)((CPU_ADDR)p_data % sizeof(CPU_INT16U));
    pkt_aligned_16 = (((modulo_16 == 0) && (prev_octet_valid == DEF_NO )) ||
                      ((modulo_16 != 0) && (prev_octet_valid == DEF_YES))) ? DEF_YES : DEF_NO;


    pdata_08 = (CPU_INT08U *)p_data;
    if (prev_octet_valid == DEF_YES) {                              /* If last octet from prev pkt buf avail,   ...     */
        sum_val_32   = (CPU_INT32U)*poctet_prev;
        sum_val_32 <<=  DEF_OCTET_NBR_BITS;                         /* ... prepend last octet from prev pkt buf ...     */

        sum_val_32  += (CPU_INT32U)*pdata_08++;
        sum_32      += (CPU_INT32U) sum_val_32;                     /* ... to first octet in cur pkt buf.               */

        size_rem    -=  sizeof(CPU_INT08U);
    }

    if (pkt_aligned_16 == DEF_YES) {                                /* If pkt data aligned on 16-bit boundary, ..       */
                                                                    /* .. calc sum with 16- & 32-bit data words.        */
        pdata_16  = (CPU_INT16U *)pdata_08;
#if (NET_CFG_OPTIMIZE == NET_OPTIMIZE_SPD)
        modulo_32 = (CPU_INT08U  )((CPU_ADDR)pdata_16 % sizeof(CPU_INT32U));    /* See Note #4.                         */
        if ((modulo_32    !=  0) &&                                 /* If leading 16-bit pkt data avail, ..             */
            (size_rem     >=  sizeof(CPU_INT16U))) {
             data_val_16   = (CPU_INT16U)*pdata_16++;
             sum_val_32    = (CPU_INT32U) NET_UTIL_HOST_TO_NET_16(data_val_16); /* Conv to net-order (see Note #5b).    */
             sum_32       += (CPU_INT32U) sum_val_32;               /* .. start calc sum with leading 16-bit data word. */
             size_rem     -=  sizeof(CPU_INT16U);
        }

#if ((defined(uC_CFG_OPTIMIZE_ASM_EN)) && \
             (uC_CFG_OPTIMIZE_ASM_EN   == DEF_ENABLED))
                                                                    /* Calc optimized 32-bit size rem.                  */
        size_rem_32_offset = (CPU_INT16U)(size_rem % sizeof(CPU_INT32U));
        size_rem_32        = (CPU_INT16U)(size_rem - size_rem_32_offset);
                                                                    /* Calc optimized 32-bit sum (see Note #6).         */
        sum_val_32         = (CPU_INT32U)NetUtil_16BitSumDataCalcAlign_32((void     *)pdata_16,
                                                                          (CPU_INT32U)size_rem_32);
        sum_32            += (CPU_INT32U)sum_val_32;
        size_rem          -= (CPU_INT32U)size_rem_32;

        pdata_08  = (CPU_INT08U *)pdata_16;
        pdata_08 +=               size_rem_32;                      /* MUST NOT cast ptr operand (see Note #7b).        */
        pdata_16  = (CPU_INT16U *)pdata_08;

#else
        pdata_32 = (CPU_INT32U *)pdata_16;
        while (size_rem >=  sizeof(CPU_INT32U)) {                   /* While pkt data aligned on 32-bit boundary; ...   */
            data_val_32  = (CPU_INT32U) *pdata_32++;                /* ... get sum data with 32-bit data words,   ...   */

            data_val_16  = (CPU_INT16U)((data_val_32 >> 16) & 0x0000FFFF);
            sum_val_32   = (CPU_INT32U)  NET_UTIL_HOST_TO_NET_16(data_val_16);  /* Conv to net-order (see Note #5b).    */
            sum_32      += (CPU_INT32U)  sum_val_32;                /* ... & calc sum with upper 16-bit data word ...   */

            data_val_16  = (CPU_INT16U) (data_val_32        & 0x0000FFFF);
            sum_val_32   = (CPU_INT32U)  NET_UTIL_HOST_TO_NET_16(data_val_16);  /* Conv to net-order (see Note #5b).    */
            sum_32      += (CPU_INT32U)  sum_val_32;                /* ...               & lower 16-bit data word.      */

            size_rem    -=  sizeof(CPU_INT32U);
        }
        pdata_16 = (CPU_INT16U *)pdata_32;
#endif
#endif

        while (size_rem >=  sizeof(CPU_INT16U)) {                   /* While pkt data aligned on 16-bit boundary; ..    */
            data_val_16  = (CPU_INT16U)*pdata_16++;
            sum_val_32   = (CPU_INT32U) NET_UTIL_HOST_TO_NET_16(data_val_16);   /* Conv to net-order (see Note #5b).    */
            sum_32      += (CPU_INT32U) sum_val_32;                 /* .. calc sum with 16-bit data words.              */
            size_rem    -=  sizeof(CPU_INT16U);
        }
        if (size_rem > 0) {
            sum_val_32   = (CPU_INT32U)(*((CPU_INT08U *)pdata_16));
        }

    } else {                                                        /* Else pkt data NOT aligned on 16-bit boundary, .. */
        while (size_rem >=  sizeof(CPU_INT16U)) {
            sum_val_32   = (CPU_INT32U)*pdata_08++;
            sum_val_32 <<=  DEF_OCTET_NBR_BITS;
            sum_val_32  += (CPU_INT32U)*pdata_08++;
            sum_32      += (CPU_INT32U) sum_val_32;                 /* .. calc sum with  8-bit data vals.               */
            size_rem    -=  sizeof(CPU_INT16U);
        }
        if (size_rem > 0) {
            sum_val_32   = (CPU_INT32U)*pdata_08;
        }
    }


/*$PAGE*/
    if (size_rem > 0) {
        if (last_pkt_buf !=  DEF_NO) {                              /* If last pkt buf, ...                             */
            sum_val_32  <<=  DEF_OCTET_NBR_BITS;                    /* ... pad odd-len pkt len (see Note #8).           */
            sum_32       += (CPU_INT32U)sum_val_32;
        } else {
           *poctet_last   = (CPU_INT08U)sum_val_32;                 /* Else rtn last octet.                             */
            DEF_BIT_SET(*psum_err, NET_UTIL_16_BIT_SUM_ERR_LAST_OCTET);
        }
    }


    return (sum_32);                                                /* Rtn 16-bit sum (see Note #5c1).                  */
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                  NetUtil_16BitOnesCplSumDataCalc()
*
* Description : Calculate 16-bit one's-complement sum on packet data.
*
*               (1) Calculates the 16-bit one's-complement sum of packet data encapsulated in :
*
*                   (a) One or more network buffers             Support non-fragmented & fragmented packets
*                   (b) Transport layer pseudo-header           See RFC #768, Section 'Fields : Checksum' &
*                                                                   RFC #793, Section 3.1 'Header Format :
*                                                                       Checksum'.
*
* Argument(s) : pdata_buf           Pointer to packet data network buffer(s) (see Notes #1a & #2).
*
*               ppseudo_hdr         Pointer to transport layer pseudo-header (see Note #1b).
*
*               pseudo_hdr_size     Size    of transport layer pseudo-header.
*
*               perr                Pointer to variable that will receive the return error code from this function :
*
*                                       NET_UTIL_ERR_NONE               16-bit one's-complement sum calculated;
*                                                                           check return value.
*                                       NET_UTIL_ERR_NULL_PTR           Argument 'pdata_buf' passed a NULL pointer.
*                                       NET_UTIL_ERR_NULL_SIZE          Packet data is a zero size.
*                                       NET_UTIL_ERR_INVALID_PROTOCOL   Invalid data packet protocol.
*                                       NET_BUF_ERR_INVALID_IX          Invalid buffer index.
*
* Return(s)   : 16-bit one's-complement sum, if NO errors.
*
*               0,                           otherwise.
*
* Caller(s)   : NetUtil_16BitOnesCplChkSumDataCalc(),
*               NetUtil_16BitOnesCplChkSumDataVerify().
*
* Note(s)     : (2) Pointer to network buffer packet NOT validated as a network buffer.  However, no memory
*                   corruption occurs since no write operations are performed.
*
*               (3) Default case already invalidated in earlier functions.  However, the default case is
*                   included as an extra precaution in case 'ProtocolHdrType' is incorrectly modified.
*
*               (4) (a) Since the 16-bit sum calculations are returned as 32-bit network-order values 
*                       (see 'NetUtil_16BitSumDataCalc()  Note #5c1'), ...
*
*                   (b) ... the one's-complement sum MUST be converted to host-order but MUST NOT be re-
*                       converted back to network-order (see 'NetUtil_16BitSumDataCalc()  Note #5c3').
*********************************************************************************************************
*/
/*$PAGE*/
static  CPU_INT16U  NetUtil_16BitOnesCplSumDataCalc (void        *pdata_buf,
                                                     void        *ppseudo_hdr,
                                                     CPU_INT16U   pseudo_hdr_size,
                                                     NET_ERR     *perr)
{
    NET_BUF      *pbuf;
    NET_BUF      *pbuf_next;
    NET_BUF_HDR  *pbuf_hdr;
    void         *p_data;
    CPU_INT32U    sum;
    CPU_INT32U    sum_val;
    CPU_INT16U    sum_ones_cpl;
    CPU_INT16U    sum_ones_cpl_host;
    CPU_INT16U    data_ix;
    CPU_INT16U    data_len;
    CPU_INT08U    sum_err;
    CPU_INT08U    octet_prev;
    CPU_INT08U    octet_last;
    CPU_BOOLEAN   octet_prev_valid;
    CPU_BOOLEAN   octet_last_valid;
    CPU_BOOLEAN   mem_buf_last;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
    CPU_BOOLEAN   mem_buf_first;
    CPU_BOOLEAN   mem_buf_null_size;
#endif


#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                     /* ----------------- VALIDATE PTR ----------------- */
    if (pdata_buf == (void *)0) {
       *perr =  NET_UTIL_ERR_NULL_PTR;
        return (0);
    }
#endif


                                                                    /* ------ CALC PKT DATA 16-BIT ONE'S-CPL SUM ------ */
    pbuf             = (NET_BUF *)pdata_buf;
    sum              =  0;
    octet_prev       =  0;
    octet_last       =  0;
    octet_prev_valid =  DEF_NO;
    octet_last_valid =  DEF_NO;
    mem_buf_last     =  DEF_NO;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
    mem_buf_first    =  DEF_YES;
#endif

    if (ppseudo_hdr != (void *)0) {                                 /* Calc pkt's pseudo-hdr 16-bit sum (see Note #1b). */
        sum_val  = NetUtil_16BitSumDataCalc((void       *) ppseudo_hdr,
                                            (CPU_INT16U  ) pseudo_hdr_size, 
                                            (CPU_INT08U *)&octet_prev,
                                            (CPU_INT08U *)&octet_last,
                                            (CPU_BOOLEAN ) octet_prev_valid,
                                            (CPU_BOOLEAN ) mem_buf_last,
                                            (CPU_INT08U *)&sum_err);
        sum     += sum_val;

        octet_last_valid = DEF_BIT_IS_SET(sum_err, NET_UTIL_16_BIT_SUM_ERR_LAST_OCTET);
        if (octet_last_valid == DEF_YES) {                          /* If last octet from pseudo-hdr avail, ...         */
            octet_prev        = octet_last;                         /* ... prepend last octet to first pkt buf.         */
            octet_prev_valid  = DEF_YES;
        } else {
            octet_prev        = 0;
            octet_prev_valid  = DEF_NO;
        }
    }

/*$PAGE*/
    while (pbuf  != (NET_BUF *)0) {                                 /* Calc ALL data pkts' 16-bit sum (see Note #1a).   */
        pbuf_hdr  = &pbuf->Hdr;
        switch (pbuf_hdr->ProtocolHdrType) {                        /* Demux pkt buf's protocol ix & len.               */
            case NET_PROTOCOL_TYPE_ICMP:
                 data_ix  = pbuf_hdr->ICMP_MsgIx;
                 data_len = pbuf_hdr->ICMP_HdrLen    + (CPU_INT16U)pbuf_hdr->DataLen;
                 break;


            case NET_PROTOCOL_TYPE_UDP:
            case NET_PROTOCOL_TYPE_TCP:
                 data_ix  = pbuf_hdr->TCP_UDP_HdrDataIx;
                 data_len = pbuf_hdr->TCP_UDP_HdrLen + (CPU_INT16U)pbuf_hdr->DataLen;
                 break;


            default:                                                /* See Note #3.                                     */
                *perr =  NET_UTIL_ERR_INVALID_PROTOCOL;
                 return (0);                                        /* Prevent 'break NOT reachable' compiler warning.  */
        }

#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
        if (data_ix == NET_BUF_IX_NONE) {
           *perr =  NET_BUF_ERR_INVALID_IX;
            return (0);
        }
#endif
        p_data       = (void    *)&pbuf->Data[data_ix];
        pbuf_next    = (NET_BUF *) pbuf_hdr->NextBufPtr;
        mem_buf_last = (pbuf_next == (NET_BUF *)0) ? DEF_YES : DEF_NO;
                                                                    /* Calc pkt buf's 16-bit sum.                       */
        sum_val      =  NetUtil_16BitSumDataCalc((void       *) p_data,
                                                 (CPU_INT16U  ) data_len, 
                                                 (CPU_INT08U *)&octet_prev,
                                                 (CPU_INT08U *)&octet_last,
                                                 (CPU_BOOLEAN ) octet_prev_valid,
                                                 (CPU_BOOLEAN ) mem_buf_last,
                                                 (CPU_INT08U *)&sum_err);

#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
        if (mem_buf_first == DEF_YES) {
            mem_buf_first  = DEF_NO;
            if (mem_buf_last == DEF_YES) {
                mem_buf_null_size = DEF_BIT_IS_SET(sum_err, NET_UTIL_16_BIT_SUM_ERR_NULL_SIZE);
                if (mem_buf_null_size != DEF_NO) {                  /* If ONLY mem buf & null size, rtn err.            */
                   *perr =  NET_UTIL_ERR_NULL_SIZE;
                    return (0);
                }
            }
        }
#endif

        if (mem_buf_last != DEF_YES) {                              /* If NOT on last pkt buf &                     ... */
            octet_last_valid = DEF_BIT_IS_SET(sum_err, NET_UTIL_16_BIT_SUM_ERR_LAST_OCTET);
            if (octet_last_valid == DEF_YES) {                      /* ...         last octet from cur  pkt buf avail,  */
                octet_prev        = octet_last;                     /* ... prepend last octet to   next pkt buf.        */
                octet_prev_valid  = DEF_YES;
            } else {
                octet_prev        = 0;
                octet_prev_valid  = DEF_NO;
            }
        }

        sum  += sum_val;
        pbuf  = pbuf_next;
    }


    while (sum >> 16) {                                             /* While 16-bit sum ovf's, ...                      */
        sum = (sum & 0x0000FFFF) + (sum >> 16);                     /* ... sum ovf bits back into 16-bit one's-cpl sum. */
    }

    sum_ones_cpl      = (CPU_INT16U)sum;
    sum_ones_cpl_host =  NET_UTIL_NET_TO_HOST_16(sum_ones_cpl);     /* Conv back to host-order  (see Note #4b).         */
   *perr              =  NET_UTIL_ERR_NONE;


    return (sum_ones_cpl_host);                                     /* Rtn 16-bit one's-cpl sum (see Note #1).          */
}

