/*
*********************************************************************************************************
*                                              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 CONNECTION MANAGEMENT
*
* Filename      : net_conn.c
* Version       : V1.89
* Programmer(s) : ITJ
*********************************************************************************************************
* Note(s)       : (1) Supports network connections for local & remote addresses of the following :
*
*                     (a) Families :
*                         (1) IPv4 Connections
*                             (A) BSD 4.x Sockets
*
*                     (b) Connection types :
*                         (1) Datagram
*                         (2) Stream
*********************************************************************************************************
*/

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

#define    NET_CONN_MODULE
#include  <net.h>


/*
*********************************************************************************************************
*                                               MODULE
*
* Note(s) : (1) See 'net_conn.h  MODULE'.
*********************************************************************************************************
*/

#ifdef  NET_CONN_MODULE_PRESENT


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


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


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

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


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


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

static  void       NetConn_Close                 (NET_CONN             *pconn);

static  void       NetConn_CloseApp              (NET_CONN             *pconn);

static  void       NetConn_CloseTransport        (NET_CONN             *pconn);


static  void       NetConn_CloseAllConnListConns (NET_CONN            **pconn_list);



static  void       NetConn_FreeHandler           (NET_CONN             *pconn);


static  void       NetConn_Clr                   (NET_CONN             *pconn);

#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
static  void       NetConn_Discard               (NET_CONN             *pconn);
#endif



static  NET_CONN  *NetConn_ListSrch              (NET_CONN            **pconn_list,
                                                  NET_CONN_LIST_TYPE    conn_list_type,
                                                  CPU_BOOLEAN           sec_srch_addr_reqd,
                                                  CPU_INT08U           *paddr_local,
                                                  CPU_INT08U           *paddr_remote);


static  void       NetConn_ChainInsert           (NET_CONN            **pconn_list,
                                                  NET_CONN             *pconn_chain);

static  void       NetConn_ChainUnlink           (NET_CONN            **pconn_list,
                                                  NET_CONN             *pconn_chain);


static  void       NetConn_Add                   (NET_CONN            **pconn_list,
                                                  NET_CONN             *pconn_chain,
                                                  NET_CONN             *pconn,
                                                  NET_CONN_LIST_TYPE    conn_list_type);

static  void       NetConn_Unlink                (NET_CONN             *pconn);


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


/*$PAGE*/
/*
*********************************************************************************************************
*                                           NetConn_Init()
*
* Description : (1) Initialize Network Connection Management Module :
*
*                   (a) Initialize network connection pool
*                   (b) Initialize network connection table
*                   (c) Initialize network connection lists
*                   (d) Initialize network connection wildcard address(s)
*                   (e) Initialize network connection statistics & error counters
*
*
* Argument(s) : none.
*
* Return(s)   : none.
*
* Caller(s)   : Net_Init().
*
*               This function is an INTERNAL network protocol suite function & MUST NOT be called by 
*               application function(s).
*
* Note(s)     : (2) Network connection pool MUST be initialized PRIOR to initializing the pool with 
*                   pointers to network connections.
*
*               (3) Network connection  addresses maintained in network-order.  Therefore, network 
*                   connection wildcard address(es) MUST be configured in network-order.
*
*               (4) Ideally, network connection address configuration comparison(s) would be calculated 
*                   at compile-time.  However, some compilers do NOT allow pre-processor directives to 
*                   include run-time macro's -- e.g. 'sizeof()'.
*********************************************************************************************************
*/
/*$PAGE*/
void  NetConn_Init (void)
{
    NET_CONN            *pconn;
    NET_CONN           **pconn_list;
    NET_CONN_QTY         i;
    NET_CONN_LIST_QTY    j;
    CPU_INT16U           k;
    CPU_INT16U           ix;
    CPU_INT16U           val_len;
    CPU_INT08U           val;
    NET_ERR              stat_err;


                                                                /* ------------- INIT NET CONN POOL/STATS ------------- */
    NetConn_PoolPtr = (NET_CONN *)0;                            /* Init-clr net conn pool (see Note #2).                */

    NetStat_PoolInit((NET_STAT_POOL   *)&NetConn_PoolStat,
                     (NET_STAT_POOL_QTY) NET_CONN_CFG_NBR_CONN,
                     (NET_ERR         *)&stat_err);


                                                                /* ---------------- INIT NET CONN TBL ----------------- */
    pconn = &NetConn_Tbl[0];
    for (i = 0; i < NET_CONN_CFG_NBR_CONN; i++) {
        pconn->Type  =  NET_CONN_TYPE_CONN;                     /* Init each net conn type/id--NEVER modify.            */
        pconn->ID    = (NET_CONN_ID)i;

        pconn->Flags =  NET_CONN_FLAG_NONE;                     /* Init each net conn as NOT used.                      */

#if (NET_DBG_CFG_MEM_CLR_EN == DEF_ENABLED)
        NetConn_Clr(pconn);
#endif

        pconn->NextConnPtr = (void     *)NetConn_PoolPtr;       /* Free each net conn to net conn pool (see Note #2).   */
        NetConn_PoolPtr    = (NET_CONN *)pconn;

        pconn++;
    }


                                                                /* --------------- INIT NET CONN LISTS ---------------- */
                                                                /* Init net conn lists.                                 */
    pconn_list = &NetConn_ServerConnListHead[0];
    for (j = 0; j < NET_CONN_CFG_PROTOCOL_MAX; j++) {
       *pconn_list = (NET_CONN *)0;
        pconn_list++;
    }

    pconn_list = &NetConn_ClientConnListHead[0];
    for (j = 0; j < NET_CONN_CFG_PROTOCOL_MAX; j++) {
       *pconn_list = (NET_CONN *)0;
        pconn_list++;
    }

                                                                /* Init net conn list ptrs.                             */
    NetConn_ConnListChainPtr     = (NET_CONN *)0;
    NetConn_ConnListConnPtr      = (NET_CONN *)0;
    NetConn_ConnListNextChainPtr = (NET_CONN *)0;
    NetConn_ConnListNextConnPtr  = (NET_CONN *)0;



/*$PAGE*/
                                                                /* ----------- INIT NET CONN WILDCARD ADDRS ----------- */
                                                                /* See Note #3.                                         */
    Mem_Clr((void     *)&NetConn_AddrWildCard[0],
            (CPU_SIZE_T) NET_CONN_CFG_ADDR_LEN);

#if (NET_CONN_CFG_FAMILY == NET_CONN_FAMILY_IP_V4_SOCK)
    if (NET_CONN_ADDR_IP_LEN_ADDR <= NET_CONN_CFG_ADDR_LEN) {   /* See Note #4.                                         */
        NetConn_AddrWildCardAvail  = DEF_YES;

        val_len = NET_CONN_ADDR_IP_LEN_ADDR;
        for (k = 0; k < val_len; k++) {
            val                      = (NET_CONN_ADDR_IP_WILD_CARD >> (k * DEF_OCTET_NBR_BITS)) & DEF_OCTET_MASK;
            ix                       =  val_len - k - 1;
            NetConn_AddrWildCard[ix] =  val;
        }

    } else {
        NetConn_AddrWildCardAvail = DEF_NO;
    }


#else
    NetConn_AddrWildCardAvail = DEF_NO;
   (void)&k;                                                    /* Prevent compiler warnings.                           */
   (void)&ix;
   (void)&val;
   (void)&val_len;
#endif



                                                                /* ---------- INIT NET CONN STAT & ERR CTRS ----------- */
#if (NET_CTR_CFG_ERR_EN                == DEF_ENABLED)
    NetConn_ErrNoneAvailCtr            =  0;
    NetConn_ErrNotUsedCtr              =  0;

    NetConn_ErrCloseCtr                =  0;

    NetConn_ErrInvalidConnCtr          =  0;
    NetConn_ErrInvalidConnAddrLenCtr   =  0;
    NetConn_ErrInvalidConnAddrInUseCtr =  0;

    NetConn_ErrInvalidFamilyCtr        =  0;

    NetConn_ErrInvalidListTypeCtr      =  0;
    NetConn_ErrInvalidListIxCtr        =  0;

#if (NET_ERR_CFG_ARG_CHK_DBG_EN        == DEF_ENABLED)
    NetConn_ErrNullPtrCtr              =  0;

    NetConn_ErrInvalidTypeCtr          =  0;
#endif
#endif
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                       NetConn_CfgAccessedTh()
*
* Description : Configure network connection accessed-promotion threshold.
*
* Argument(s) : nbr_access      Desired number of accesses before network connection is promoted.
*
* Return(s)   : DEF_OK, network connection promotion threshold configured.
*
* Caller(s)   : Net_InitDflt(),
*               Application.
*
*               This function is a network protocol suite application interface (API) function & MAY be 
*               called by application function(s).
*
* Note(s)     : none.
*********************************************************************************************************
*/

CPU_BOOLEAN  NetConn_CfgAccessedTh (CPU_INT16U  nbr_access)
{
#if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL)
    CPU_SR  cpu_sr;
#endif


#if (NET_CONN_ACCESSED_TH_MIN > DEF_INT_16U_MIN_VAL)
    if (nbr_access < NET_CONN_ACCESSED_TH_MIN) {
        nbr_access = NET_CONN_ACCESSED_TH_MIN;
    }
#endif
#if (NET_CONN_ACCESSED_TH_MAX < DEF_INT_16U_MAX_VAL)
    if (nbr_access > NET_CONN_ACCESSED_TH_MAX) {
        nbr_access = NET_CONN_ACCESSED_TH_MAX;
    }
#endif

    CPU_CRITICAL_ENTER();
    NetConn_AccessedTh_nbr = nbr_access;
    CPU_CRITICAL_EXIT();

    return (DEF_OK);
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                            NetConn_Get()
*
* Description : (1) Allocate & initialize a network connection :
*
*                   (a) Get      a network connection
*                   (b) Validate   network connection
*                   (c) Initialize network connection
*                   (d) Update     network connection pool statistics
*                   (e) Return network connection handle identifier
*                         OR
*                       Null identifier & error code, on failure
*
*               (2) The network connection pool is implemented as a stack :
*
*                   (a) 'NetConn_PoolPtr' points to the head of the network connection pool.
*
*                   (b) Connections' 'NextConnPtr's link each connection to form the connection pool stack.
*
*                   (c) Connections are inserted & removed at the head of        the connection pool stack.
*
*
*                                     Connections are
*                                    inserted & removed
*                                        at the head
*                                      (see Note #2c)
*
*                                             |               NextConnPtr
*                                             |             (see Note #2b)
*                                             v                    |
*                                                                  |
*                                          -------       -------   v   -------       -------
*                     Connection Pool ---->|     |------>|     |------>|     |------>|     |
*                         Pointer          |     |       |     |       |     |       |     |
*                                          |     |       |     |       |     |       |     |
*                      (see Note #2a)      -------       -------       -------       -------
*
*                                          |                                               |
*                                          |<--------- Pool of Free Connections ---------->|
*                                          |                (see Note #2)                  |
*
*
* Argument(s) : perr        Pointer to variable that will receive the return error code from this function :
*
*                               NET_CONN_ERR_NONE               Network connection successfully allocated &
*                                                                   initialized.
*                               NET_CONN_ERR_NONE_AVAIL         NO available network connections to allocate.
*                               NET_CONN_ERR_INVALID_FAMILY     Invalid network connection family.
*                               NET_CONN_ERR_INVALID_TYPE       Invalid network connection type.
*                               NET_CONN_ERR_INVALID_LIST_IX    Invalid network connection list index.
*
* Return(s)   : Connection handle identifier, if NO errors.
*
*               NET_CONN_ID_NONE,             otherwise.
*
* Caller(s)   : NetSock_BindHandler(),
*               NetTCP_RxPktConnHandlerListen().
*
*               This function is an INTERNAL network protocol suite function & MUST NOT be called by 
*               application function(s).
*
* Note(s)     : (3) (a) Network connection pool is accessed by 'NetConn_PoolPtr' during execution of
*
*                       (1) NetConn_Init()
*                       (2) NetConn_Get()
*                       (3) NetConn_FreeHandler()
*
*                   (b) Since the primary tasks of the network protocol suite are prevented from running 
*                       concurrently (see 'net.h  Note #2'), it is NOT necessary to protect the shared 
*                       resources of the network connection pool since no asynchronous access from other 
*                       network tasks is possible.
*********************************************************************************************************
*/
/*$PAGE*/
NET_CONN_ID  NetConn_Get (NET_CONN_FAMILY    family,
                          NET_CONN_LIST_IX   protocol_ix,
                          NET_ERR           *perr)
{
#if ((NET_CTR_CFG_ERR_EN      == DEF_ENABLED)                    && \
     (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
    CPU_SR        cpu_sr;
#endif
    NET_CONN     *pconn;
    NET_CONN_ID   conn_id;
    NET_ERR       stat_err;


                                                                /* -------------- VALIDATE NET CONN ARGS -------------- */
    switch (family) {
#if (NET_CONN_CFG_FAMILY == NET_CONN_FAMILY_IP_V4_SOCK)
        case NET_CONN_FAMILY_IP_V4_SOCK:
             switch (protocol_ix) {
                 case NET_CONN_LIST_IX_IP_V4_SOCK_UDP:
#ifdef  NET_TCP_MODULE_PRESENT
                 case NET_CONN_LIST_IX_IP_V4_SOCK_TCP:
#endif
                      break;


                 default:
                      NET_CTR_ERR_INC(NetConn_ErrInvalidListIxCtr);
                     *perr =  NET_CONN_ERR_INVALID_LIST_IX;
                      return (NET_CONN_ID_NONE);                /* Prevent 'break NOT reachable' compiler warning.      */
             }
             break;
#endif

        case NET_CONN_FAMILY_NONE:
        default:
             NET_CTR_ERR_INC(NetConn_ErrInvalidFamilyCtr);
            *perr =  NET_CONN_ERR_INVALID_FAMILY;
             return (NET_CONN_ID_NONE);                         /* Prevent 'break NOT reachable' compiler warning.      */
    }

#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
    if (protocol_ix >= NET_CONN_CFG_PROTOCOL_MAX) {
        NET_CTR_ERR_INC(NetConn_ErrInvalidListIxCtr);
       *perr =  NET_CONN_ERR_INVALID_LIST_IX;
        return (NET_CONN_ID_NONE);
    }
#endif


                                                                /* ------------------- GET NET CONN ------------------- */
    if (NetConn_PoolPtr != (NET_CONN *)0) {                     /* If net conn pool NOT empty, get net conn from pool.  */
        pconn            = (NET_CONN *)NetConn_PoolPtr;
        NetConn_PoolPtr  = (NET_CONN *)pconn->NextConnPtr;

    } else {                                                    /* If none avail, rtn err.                              */
        NET_CTR_ERR_INC(NetConn_ErrNoneAvailCtr);
       *perr =  NET_CONN_ERR_NONE_AVAIL;
        return (NET_CONN_ID_NONE);
    }

#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                 /* ---------------- VALIDATE NET CONN ----------------- */
    if (pconn->Type != NET_CONN_TYPE_CONN) {
        NetConn_Discard(pconn);
        NET_CTR_ERR_INC(NetConn_ErrInvalidTypeCtr);
       *perr =  NET_CONN_ERR_INVALID_TYPE;
        return (NET_CONN_ID_NONE);
    }
#endif

                                                                /* ------------------ INIT NET CONN ------------------- */
    NetConn_Clr(pconn);
    DEF_BIT_SET(pconn->Flags, NET_CONN_FLAG_USED);              /* Set net conn as used.                                */
    pconn->Family         = family;
    pconn->ProtocolListIx = protocol_ix;

                                                                /* ------------ UPDATE NET CONN POOL STATS ------------ */
    NetStat_PoolEntryUsedInc(&NetConn_PoolStat, &stat_err);

                                                                /* ----------------- RTN NET CONN ID ------------------ */
    conn_id = pconn->ID;
   *perr    = NET_CONN_ERR_NONE;

    return (conn_id);
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                           NetConn_Free()
*
* Description : Free a network connection.
*
*               (1) Network connection free ONLY frees but does NOT close any connections.
*
*
* Argument(s) : conn_id     Handle identifier of network connection to free.
*
* Return(s)   : none.
*
* Caller(s)   : various.
*
*               This function is an INTERNAL network protocol suite function & MUST NOT be called by 
*               application function(s).
*
* Note(s)     : (2) #### To prevent freeing a network connection already freed via previous network
*                   connection free, NetConn_Free() checks if the network connection is used BEFORE 
*                   freeing the network connection.
*
*                   This prevention is only best-effort since any invalid duplicate network connection 
*                   frees MAY be asynchronous to potentially valid network connection gets.  Thus the 
*                   invalid network connection free(s) MAY corrupt the network connection's valid
*                   operation(s).
*
*                   However, since the primary tasks of the network protocol suite are prevented from
*                   running concurrently (see 'net.h  Note #2'), it is NOT necessary to protect network
*                   connection resources from possible corruption since no asynchronous access from
*                   other network tasks is possible.
*********************************************************************************************************
*/

void  NetConn_Free (NET_CONN_ID  conn_id)
{
#if  (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
    NET_ERR    err;
#endif
    NET_CONN  *pconn;

                                                                /* ---------------- VALIDATE NET CONN ----------------- */
    if (conn_id == NET_CONN_ID_NONE) {
        return;
    }

#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                 /* -------------- VALIDATE NET CONN USED -------------- */
   (void)NetConn_IsUsed(conn_id, &err);
    if (err != NET_CONN_ERR_NONE) {                             /* If net conn NOT used, ...                            */
        return;                                                 /* ... rtn but do NOT free (see Note #2).               */
    }
#endif

                                                                /* ------------------ FREE NET CONN ------------------- */
    pconn = &NetConn_Tbl[conn_id];
    NetConn_FreeHandler(pconn);
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                       NetConn_CloseFromApp()
*
* Description : (1) Close a network connection from application layer :
*
*                   (a) Close transport connection, if requested                            See Note #3c
*                   (b) Clear network   connection's reference to application connection    See Note #3c
*                   (c) Free  network   connection, if necessary
*
*
* Argument(s) : conn_id                 Handle identifier of network connection to close.
*
*               close_conn_transport    Indicate whether to close transport connection :
*
*                                           DEF_YES                    Close transport connection.
*                                           DEF_NO              Do NOT close transport connection.
*
* Return(s)   : none.
*
* Caller(s)   : NetSock_CloseConn(),
*               NetSock_CloseSockHandler(),
*               NetSock_ConnAcceptQ_Clr().
*
*               This function is an INTERNAL network protocol suite function & MUST NOT be called by 
*               application function(s).
*
* Note(s)     : (2) #### To prevent closing a network connection already closed via previous network
*                   connection close, NetConn_CloseFromApp() checks if the network connection is used 
*                   BEFORE closing the network connection.
*
*                   This prevention is only best-effort since any invalid duplicate network connection 
*                   closes MAY be asynchronous to potentially valid network connection gets.  Thus the 
*                   invalid network connection close(s) MAY corrupt the network connection's valid
*                   operation(s).
*
*                   However, since the primary tasks of the network protocol suite are prevented from
*                   running concurrently (see 'net.h  Note #2'), it is NOT necessary to protect network
*                   connection resources from possible corruption since no asynchronous access from
*                   other network tasks is possible.
*
*                   (a) Network connection(s) MAY already be closed AFTER other network connection 
*                       close operations & MUST be validated as used BEFORE any subsequent network 
*                       connection close operation(s).
*
*               (3) (a) Network connections are considered connected if any of the following network 
*                       connections are valid :
*
*                       (1) Application layer connection
*                       (2) Transport   layer connection
*
*                               (A) Network connections which ONLY reference application layer clone 
*                                   connection(s) are NOT considered connected since the actual non-
*                                   cloned application connection MAY or MAY NOT reference the cloned
*                                   network connection.
*
*                   (b) Since NetConn_CloseFromApp() actively closes the application layer connection,
*                       network connections need only validate the remaining transport layer connection
*                       as connected.
*
*                   (c) Since network connection(s) connection validation determines, in part, when to
*                       close the network connection (see Note #3a), & since NetConn_CloseFromTransport() 
*                       may indirectly call NetConn_CloseFromApp(); clearing the network connection's 
*                       application layer connection handle identifier MUST follow the closing of the 
*                       transport   layer connection to prevent re-closing the network connection.
*********************************************************************************************************
*/
/*$PAGE*/
void  NetConn_CloseFromApp (NET_CONN_ID  conn_id,
                            CPU_BOOLEAN  close_conn_transport)
{
    CPU_BOOLEAN   used;
    CPU_BOOLEAN   connd;
    CPU_BOOLEAN   free;
    NET_CONN     *pconn;
    NET_ERR       err;

                                                                    /* -------------- VALIDATE NET CONN --------------- */
    if (conn_id == NET_CONN_ID_NONE) {
        return;
    }

#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                     /* ------------ VALIDATE NET CONN USED ------------ */
   (void)NetConn_IsUsed(conn_id, &err);
    if (err != NET_CONN_ERR_NONE) {                                 /* If net conn NOT used, ...                        */
        return;                                                     /* ... rtn but do NOT close (see Note #2).          */
    }
#endif


    pconn = &NetConn_Tbl[conn_id];

                                                                    /* ------------- CLOSE TRANSPORT CONN ------------- */
    if (close_conn_transport == DEF_YES) {                          
        NetConn_CloseTransport(pconn);                              /* Close transport conn, if req'd.                  */
        used  =  DEF_BIT_IS_SET(pconn->Flags, NET_CONN_FLAG_USED);  /* If still used (see Note #2a), free net conn ...  */
        free  = (used == DEF_YES) ? DEF_YES : DEF_NO;               /* ... since app & transport conns closed.          */

    } else {                                                        /* Else chk net conn conn'd (see Note #3b).         */
        connd = (pconn->ID_Transport != NET_CONN_ID_NONE) ? DEF_YES : DEF_NO;
        free  =  (connd != DEF_YES) ? DEF_YES : DEF_NO;             /* Free net conn, if NOT conn'd.                    */
    }

                                                                    /* ---------------- CLOSE APP CONN ---------------- */
    NetConn_ID_AppSet(conn_id, NET_CONN_ID_NONE, &err);             /* Clr net conn's app conn id (see Note #3c).       */

                                                                    /* ---------------- FREE NET CONN ----------------- */
    if (free == DEF_YES) {
        NetConn_FreeHandler(pconn);                                 /* Free net conn, if req'd.                         */
    }
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                    NetConn_CloseFromTransport()
*
* Description : (1) Close a network connection from transport layer :
*
*                   (a) Close application connection, if requested                          See Note #3c
*                   (b) Clear network     connection's reference to transport connection    See Note #3c
*                   (c) Free  network     connection, if necessary
*
*
* Argument(s) : conn_id             Handle identifier of network connection to close.
*
*               close_conn_app      Indicate whether to close application connection :
*
*                                       DEF_YES                        Close application connection.
*                                       DEF_NO                  Do NOT close application connection.
*
* Return(s)   : none.
*
* Caller(s)   : NetTCP_ConnClose().
*
*               This function is an INTERNAL network protocol suite function & MUST NOT be called by 
*               application function(s).
*
* Note(s)     : (2) #### To prevent closing a network connection already closed via previous network
*                   connection close, NetConn_CloseFromTransport() checks if the network connection 
*                   is used BEFORE closing the network connection.
*
*                   This prevention is only best-effort since any invalid duplicate network connection 
*                   closes MAY be asynchronous to potentially valid network connection gets.  Thus the 
*                   invalid network connection close(s) MAY corrupt the network connection's valid
*                   operation(s).
*
*                   However, since the primary tasks of the network protocol suite are prevented from
*                   running concurrently (see 'net.h  Note #2'), it is NOT necessary to protect network
*                   connection resources from possible corruption since no asynchronous access from
*                   other network tasks is possible.
*
*                   (a) Network connection(s) MAY already be closed AFTER other network connection 
*                       close operations & MUST be validated as used BEFORE any subsequent network 
*                       connection close operation(s).
*
*               (3) (a) Network connections are considered connected if any of the following network 
*                       connections are valid :
*
*                       (1) Application layer connection
*                       (2) Transport   layer connection
*
*                               (A) Network connections which ONLY reference application layer clone 
*                                   connection(s) are NOT considered connected since the actual non-
*                                   cloned application connection MAY or MAY NOT reference the cloned
*                                   network connection.
*
*                   (b) Since NetConn_CloseFromTransport() actively closes the transport layer connection,
*                       network connections need only validate the remaining application layer connection
*                       as connected.
*
*                   (c) Since network connection(s) connection validation determines, in part, when to
*                       close the network connection (see Note #3a), & since NetConn_CloseFromApp() may
*                       indirectly call NetConn_CloseFromTransport(); clearing the network connection's 
*                       transport   layer connection handle identifier MUST follow the closing of the 
*                       application layer connection to prevent re-closing the network connection.
*********************************************************************************************************
*/
/*$PAGE*/
void  NetConn_CloseFromTransport (NET_CONN_ID  conn_id,
                                  CPU_BOOLEAN  close_conn_app)
{
    CPU_BOOLEAN   used;
    CPU_BOOLEAN   connd;
    CPU_BOOLEAN   free;
    NET_CONN     *pconn;
    NET_ERR       err;

                                                                    /* -------------- VALIDATE NET CONN --------------- */
    if (conn_id == NET_CONN_ID_NONE) {
        return;
    }

#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                     /* ------------ VALIDATE NET CONN USED ------------ */
   (void)NetConn_IsUsed(conn_id, &err);
    if (err != NET_CONN_ERR_NONE) {                                 /* If net conn NOT used, ...                        */
        return;                                                     /* ... rtn but do NOT close (see Note #2).          */
    }
#endif


    pconn = &NetConn_Tbl[conn_id];

                                                                    /* ---------------- CLOSE APP CONN ---------------- */
    if (close_conn_app == DEF_YES) {                          
        NetConn_CloseApp(pconn);                                    /* Close app conn, if req'd.                        */
        used  =  DEF_BIT_IS_SET(pconn->Flags, NET_CONN_FLAG_USED);  /* If still used (see Note #2a), free net conn ...  */
        free  = (used == DEF_YES) ? DEF_YES : DEF_NO;               /* ... since app & transport conns closed.          */

    } else {                                                        /* Else chk net conn conn'd (see Note #3b).         */
        connd = (pconn->ID_App != NET_CONN_ID_NONE) ? DEF_YES : DEF_NO;
        free  =  (connd != DEF_YES) ? DEF_YES : DEF_NO;             /* Free net conn, if NOT conn'd.                    */
    }

                                                                    /* ------------- CLOSE TRANSPORT CONN ------------- */
    NetConn_ID_TransportSet(conn_id, NET_CONN_ID_NONE, &err);       /* Clr net conn's transport conn id (see Note #3c). */

                                                                    /* ---------------- FREE NET CONN ----------------- */
    if (free == DEF_YES) {
        NetConn_FreeHandler(pconn);                                 /* Free net conn, if req'd.                         */
    }
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                       NetConn_CloseAllConns()
*
* Description : Close ALL network connections.
*
* Argument(s) : none.
*
* Return(s)   : none.
*
* Caller(s)   : Application.
*
*               This function is a network protocol suite application interface (API) function & MAY
*               be called by application function(s) [see also Note #2].
*
* Note(s)     : (1) (a) Certain circumstances may require that :
*
*                       (1) ALL network protocol suite connections close; ...
*                       (2) All pending network &/or application connection function(s) SHOULD :
*                           (A) Abort, immediately if possible; ...
*                           (B) Return appropriate closed error code(s).
*
*                   (b) The following example(s) list when to close all network connections :
*
*                       (1) RFC #2131, Section 4.4.5 states that "if the [DHCP] client is given a
*                           new network address, it MUST NOT continue using the previous network
*                           address and SHOULD notify the local users of the problem".
*
*                           Therefore, ALL network connections based on a previous network address
*                           MUST be closed.
*
*               (2) NetConn_CloseAllConns() is called by application function(s) & ... :
*
*                   (a) MUST NOT be called with the global network lock already acquired; ...
*                   (b) MUST block ALL other network protocol tasks by pending on & acquiring the global
*                       network lock (see 'net.h  Note #2').
*
*                   This is required since an application's network protocol suite API function access is 
*                   asynchronous to other network protocol tasks.
*
*                   See also 'NetConn_CloseAllConnsHandler()  Note #1'.
*********************************************************************************************************
*/

void  NetConn_CloseAllConns (void)
{
    NET_ERR  err;


    NetOS_Lock(&err);                                           /* Acquire net lock (see Note #2b).                     */
    if (err != NET_OS_ERR_NONE) {
        return;
    }

    NetConn_CloseAllConnsHandler();                             /* Close all net conns.                                 */

    NetOS_Unlock();                                             /* Release net lock.                                    */
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                   NetConn_CloseAllConnsHandler()
*
* Description : Close ALL network connections in ALL network connection lists.
*
* Argument(s) : none.
*
* Return(s)   : none.
*
* Caller(s)   : NetConn_CloseAllConns().
*
*               This function is an INTERNAL network protocol suite function & MUST NOT be called by 
*               application function(s) [see also Note #1].
*
* Note(s)     : (1) NetConn_CloseAllConnsHandler() is called by network protocol suite function(s) &
*                   MUST be called with the global network lock already acquired.
*
*                   See also 'NetConn_CloseAllConns()  Note #2'.
*********************************************************************************************************
*/

void  NetConn_CloseAllConnsHandler (void)
{
    NET_CONN           **pconn_list;
    NET_CONN_LIST_QTY    i;

                                                                /* -------- CLOSE SERVER CONN LIST'S NET CONNS -------- */
    pconn_list = &NetConn_ServerConnListHead[0];
    for (i = 0; i < NET_CONN_CFG_PROTOCOL_MAX; i++) {
        NetConn_CloseAllConnListConns(pconn_list);
       *pconn_list = (NET_CONN *)0;
        pconn_list++;
    }
                                                                /* -------- CLOSE CLIENT CONN LIST'S NET CONNS -------- */
    pconn_list = &NetConn_ClientConnListHead[0];
    for (i = 0; i < NET_CONN_CFG_PROTOCOL_MAX; i++) {
        NetConn_CloseAllConnListConns(pconn_list);
       *pconn_list = (NET_CONN *)0;
        pconn_list++;
    }
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                         NetConn_ID_AppGet()
*
* Description : Get a network connection's application layer handle identifier.
*
* Argument(s) : conn_id     Handle identifier of network connection to get application layer handle identifier.
*
*               perr        Pointer to variable that will receive the return error code from this function :
*
*                               NET_CONN_ERR_NONE               Network connection handle identifier get
*                                                                   successful.
*
*                                                               ---- RETURNED BY NetConn_IsUsed() : ----
*                               NET_ERR_INIT_INCOMPLETE         Network initialization NOT complete.
*                               NET_CONN_ERR_INVALID_CONN       Invalid network connection number.
*                               NET_CONN_ERR_NOT_USED           Network connection NOT currently used.
*
* Return(s)   : Network connection's application layer handle identifier, if NO errors.
*
*               NET_CONN_ID_NONE,                                         otherwise.
*
* Caller(s)   : various.
*
*               This function is an INTERNAL network protocol suite function & SHOULD NOT be called by 
*               application function(s).
*
* Note(s)     : none.
*********************************************************************************************************
*/

NET_CONN_ID  NetConn_ID_AppGet (NET_CONN_ID   conn_id,
                                NET_ERR      *perr)
{
    NET_CONN     *pconn;
    NET_CONN_ID   conn_id_app;

                                                                /* ---------------- VALIDATE NET CONN ----------------- */
    if (conn_id == NET_CONN_ID_NONE) {
       *perr =  NET_CONN_ERR_NONE;
        return (NET_CONN_ID_NONE);
    }

#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                 /* -------------- VALIDATE NET CONN USED -------------- */
   (void)NetConn_IsUsed(conn_id, perr);
    if (*perr != NET_CONN_ERR_NONE) {
         return (NET_CONN_ID_NONE);
    }
#endif


    pconn       = &NetConn_Tbl[conn_id];
    conn_id_app =  pconn->ID_App;                               /* Get net conn's app id.                               */


   *perr =  NET_CONN_ERR_NONE;

    return (conn_id_app);
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                         NetConn_ID_AppSet()
*
* Description : Set a network connection's application layer handle identifier.
*
* Argument(s) : conn_id         Handle identifier of network connection to set application layer handle
*                                   identifier.
*
*               conn_id_app     Connection's application layer handle identifier.
*
*               perr        Pointer to variable that will receive the return error code from this function :
*
*                               NET_CONN_ERR_NONE               Network connection's handle identifier
*                                                                   successfully set.
*
*                                                               --- RETURNED BY NetConn_IsUsed() : ---
*                               NET_ERR_INIT_INCOMPLETE         Network initialization NOT complete.
*                               NET_CONN_ERR_INVALID_CONN       Invalid network connection number.
*                               NET_CONN_ERR_NOT_USED           Network connection NOT currently used.
*
* Return(s)   : none.
*
* Caller(s)   : various.
*
*               This function is an INTERNAL network protocol suite function & MUST NOT be called by 
*               application function(s).
*
* Note(s)     : none.
*********************************************************************************************************
*/

void  NetConn_ID_AppSet (NET_CONN_ID   conn_id,
                         NET_CONN_ID   conn_id_app,
                         NET_ERR      *perr)
{
#if ((NET_CTR_CFG_ERR_EN      == DEF_ENABLED)                    && \
     (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
    CPU_SR     cpu_sr;
#endif
    NET_CONN  *pconn;

                                                                /* ---------------- VALIDATE NET CONN ----------------- */
    if (conn_id == NET_CONN_ID_NONE) {
       *perr = NET_CONN_ERR_NONE;
        return;
    }

#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                 /* -------------- VALIDATE NET CONN USED -------------- */
   (void)NetConn_IsUsed(conn_id, perr);
    if (*perr != NET_CONN_ERR_NONE) {
         return;
    }
#endif

                                                                /* --------------- VALIDATE APP CONN ID --------------- */
    if (conn_id_app < NET_CONN_ID_NONE) {
        NET_CTR_ERR_INC(NetConn_ErrInvalidConnCtr);
       *perr = NET_CONN_ERR_INVALID_CONN;
        return;
    }

    pconn         = &NetConn_Tbl[conn_id];
    pconn->ID_App =  conn_id_app;                               /* Set net conn's app id.                               */


   *perr = NET_CONN_ERR_NONE;
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                      NetConn_ID_AppCloneGet()
*
* Description : Get a network connection's application layer clone handle identifier.
*
* Argument(s) : conn_id     Handle identifier of network connection to get application layer clone handle
*                               identifier.
*
*               perr        Pointer to variable that will receive the return error code from this function :
*
*                               NET_CONN_ERR_NONE               Network connection handle identifier get
*                                                                   successful.
*
*                                                               ---- RETURNED BY NetConn_IsUsed() : ----
*                               NET_ERR_INIT_INCOMPLETE         Network initialization NOT complete.
*                               NET_CONN_ERR_INVALID_CONN       Invalid network connection number.
*                               NET_CONN_ERR_NOT_USED           Network connection NOT currently used.
*
* Return(s)   : Network connection's application layer clone handle identifier, if NO errors.
*
*               NET_CONN_ID_NONE,                                               otherwise.
*
* Caller(s)   : various.
*
*               This function is an INTERNAL network protocol suite function & SHOULD NOT be called by 
*               application function(s).
*
* Note(s)     : none.
*********************************************************************************************************
*/

NET_CONN_ID  NetConn_ID_AppCloneGet (NET_CONN_ID   conn_id,
                                     NET_ERR      *perr)
{
    NET_CONN     *pconn;
    NET_CONN_ID   conn_id_app_clone;

                                                                /* ---------------- VALIDATE NET CONN ----------------- */
    if (conn_id == NET_CONN_ID_NONE) {
       *perr =  NET_CONN_ERR_NONE;
        return (NET_CONN_ID_NONE);
    }

#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                 /* -------------- VALIDATE NET CONN USED -------------- */
   (void)NetConn_IsUsed(conn_id, perr);
    if (*perr != NET_CONN_ERR_NONE) {
         return (NET_CONN_ID_NONE);
    }
#endif


    pconn             = &NetConn_Tbl[conn_id];
    conn_id_app_clone =  pconn->ID_AppClone;                    /* Get net conn's app clone id.                         */


   *perr =  NET_CONN_ERR_NONE;

    return (conn_id_app_clone);
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                      NetConn_ID_AppCloneSet()
*
* Description : Set a network connection's application layer clone handle identifier.
*
* Argument(s) : conn_id         Handle identifier of network connection to set application layer clone 
*                                   handle identifier.
*
*               conn_id_app     Connection's application layer handle identifier.
*
*               perr        Pointer to variable that will receive the return error code from this function :
*
*                               NET_CONN_ERR_NONE               Network connection's handle identifier
*                                                                   successfully set.
*
*                                                               --- RETURNED BY NetConn_IsUsed() : ---
*                               NET_ERR_INIT_INCOMPLETE         Network initialization NOT complete.
*                               NET_CONN_ERR_INVALID_CONN       Invalid network connection number.
*                               NET_CONN_ERR_NOT_USED           Network connection NOT currently used.
*
* Return(s)   : none.
*
* Caller(s)   : various.
*
*               This function is an INTERNAL network protocol suite function & MUST NOT be called by 
*               application function(s).
*
* Note(s)     : none.
*********************************************************************************************************
*/

void  NetConn_ID_AppCloneSet (NET_CONN_ID   conn_id,
                              NET_CONN_ID   conn_id_app,
                              NET_ERR      *perr)
{
#if ((NET_CTR_CFG_ERR_EN      == DEF_ENABLED)                    && \
     (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
    CPU_SR     cpu_sr;
#endif
    NET_CONN  *pconn;

                                                                /* ---------------- VALIDATE NET CONN ----------------- */
    if (conn_id == NET_CONN_ID_NONE) {
       *perr = NET_CONN_ERR_NONE;
        return;
    }

#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                 /* -------------- VALIDATE NET CONN USED -------------- */
   (void)NetConn_IsUsed(conn_id, perr);
    if (*perr != NET_CONN_ERR_NONE) {
         return;
    }
#endif

                                                                /* --------------- VALIDATE APP CONN ID --------------- */
    if (conn_id_app < NET_CONN_ID_NONE) {
        NET_CTR_ERR_INC(NetConn_ErrInvalidConnCtr);
       *perr = NET_CONN_ERR_INVALID_CONN;
        return;
    }

    pconn              = &NetConn_Tbl[conn_id];
    pconn->ID_AppClone =  conn_id_app;                          /* Set net conn's app clone id.                         */


   *perr = NET_CONN_ERR_NONE;
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                      NetConn_ID_TransportGet()
*
* Description : Get a network connection's transport layer handle identifier.
*
* Argument(s) : conn_id     Handle identifier of network connection to get transport layer handle identifier.
*
*               perr        Pointer to variable that will receive the return error code from this function :
*
*                               NET_CONN_ERR_NONE               Network connection handle identifier get
*                                                                   successful.
*
*                                                               ---- RETURNED BY NetConn_IsUsed() : ----
*                               NET_ERR_INIT_INCOMPLETE         Network initialization NOT complete.
*                               NET_CONN_ERR_INVALID_CONN       Invalid network connection number.
*                               NET_CONN_ERR_NOT_USED           Network connection NOT currently used.
*
* Return(s)   : Network connection's transport layer handle identifier, if NO errors.
*
*               NET_CONN_ID_NONE,                                       otherwise.
*
* Caller(s)   : various.
*
*               This function is an INTERNAL network protocol suite function & SHOULD NOT be called by 
*               application function(s).
*
* Note(s)     : none.
*********************************************************************************************************
*/

NET_CONN_ID  NetConn_ID_TransportGet (NET_CONN_ID   conn_id,
                                      NET_ERR      *perr)
{
    NET_CONN     *pconn;
    NET_CONN_ID   conn_id_transport;

                                                                /* ---------------- VALIDATE NET CONN ----------------- */
    if (conn_id == NET_CONN_ID_NONE) {
       *perr =  NET_CONN_ERR_NONE;
        return (NET_CONN_ID_NONE);
    }

#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                 /* -------------- VALIDATE NET CONN USED -------------- */
   (void)NetConn_IsUsed(conn_id, perr);
    if (*perr != NET_CONN_ERR_NONE) {
         return (NET_CONN_ID_NONE);
    }
#endif


    pconn             = &NetConn_Tbl[conn_id];
    conn_id_transport =  pconn->ID_Transport;                   /* Get net conn's transport id.                         */


   *perr =  NET_CONN_ERR_NONE;

    return (conn_id_transport);
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                      NetConn_ID_TransportSet()
*
* Description : Set a network connection's transport layer handle identifier.
*
* Argument(s) : conn_id             Handle identifier of network connection to set transport layer handle
*                                       identifier.
*
*               conn_id_transport   Connection's transport layer handle identifier.
*
*               perr        Pointer to variable that will receive the return error code from this function :
*
*                               NET_CONN_ERR_NONE               Network connection's handle identifier
*                                                                   successfully set.
*
*                                                               --- RETURNED BY NetConn_IsUsed() : ---
*                               NET_ERR_INIT_INCOMPLETE         Network initialization NOT complete.
*                               NET_CONN_ERR_INVALID_CONN       Invalid network connection number.
*                               NET_CONN_ERR_NOT_USED           Network connection NOT currently used.
*
* Return(s)   : none.
*
* Caller(s)   : various.
*
*               This function is an INTERNAL network protocol suite function & MUST NOT be called by 
*               application function(s).
*
* Note(s)     : none.
*********************************************************************************************************
*/

void  NetConn_ID_TransportSet (NET_CONN_ID   conn_id,
                               NET_CONN_ID   conn_id_transport,
                               NET_ERR      *perr)
{
#if ((NET_CTR_CFG_ERR_EN      == DEF_ENABLED)                    && \
     (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
    CPU_SR     cpu_sr;
#endif
    NET_CONN  *pconn;

                                                                /* ---------------- VALIDATE NET CONN ----------------- */
    if (conn_id == NET_CONN_ID_NONE) {
       *perr = NET_CONN_ERR_NONE;
        return;
    }

#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                 /* -------------- VALIDATE NET CONN USED -------------- */
   (void)NetConn_IsUsed(conn_id, perr);
    if (*perr != NET_CONN_ERR_NONE) {
         return;
    }
#endif

                                                                /* ------------ VALIDATE TRANSPORT CONN ID ------------ */
    if (conn_id_transport < NET_CONN_ID_NONE) {
        NET_CTR_ERR_INC(NetConn_ErrInvalidConnCtr);
       *perr = NET_CONN_ERR_INVALID_CONN;
        return;
    }

    pconn               = &NetConn_Tbl[conn_id];
    pconn->ID_Transport =  conn_id_transport;                   /* Set net conn's transport id.                         */


   *perr = NET_CONN_ERR_NONE;
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                       NetConn_AddrLocalGet()
*
* Description : Get a network connection's local address.
*
* Argument(s) : conn_id         Handle identifier of network connection to get local address.
*
*               paddr_local     Pointer to variable that will receive the return  local address (see Note #1),
*                                   if NO errors.
*
*               paddr_len       Pointer to a variable to ... :
*                              
*                                   (a) Pass the size of the address buffer pointed to by 'paddr_local'.
*                                   (b) Return the actual local address length, if NO errors;
*                                       Return 0,                               otherwise.
*
*                               See also Note #2.
*
*               perr        Pointer to variable that will receive the return error code from this function :
*
*                               NET_CONN_ERR_NONE                   Network connection address get successful.
*                               NET_CONN_ERR_NULL_PTR               Argument 'paddr_local'/'paddr_len'
*                                                                       passed a NULL pointer.
*                               NET_CONN_ERR_INVALID_ADDR_LEN       Invalid network connection address length.
*                               NET_CONN_ERR_ADDR_NOT_USED          Network connection address NOT in use.
*
*                                                                   ----- RETURNED BY NetConn_IsUsed() : -----
*                               NET_ERR_INIT_INCOMPLETE             Network initialization NOT complete.
*                               NET_CONN_ERR_INVALID_CONN           Invalid network connection number.
*                               NET_CONN_ERR_NOT_USED               Network connection NOT currently used.
*
* Return(s)   : none.
*
* Caller(s)   : NetSock_ConnHandlerStream(),
*               NetSock_ConnHandlerAddrRemoteValidate(),
*               NetSock_TxDataHandlerDatagram(),
*               NetSock_FreeAddr(),
*               NetTCP_TxConnPrepareSegAddrs().
*
*               This function is an INTERNAL network protocol suite function & SHOULD NOT be called by 
*               application function(s).
*
* Note(s)     : (1) Network connection addresses maintained in network-order.
*
*               (2) (a) Since 'paddr_len' parameter is both an input & output parameter (see 'Argument(s) :
*                       paddr_len'), ...
*
*                       (1) its input value, prior to use, MUST be ...
*                           (A) saved, &                           ...
*                           (B) validated;                         ...
*
*                       (2) while its output value MUST be initially configured to return a default error
*                           value in case of any function exit due to error/fault conditions.
*
*                   (b) In the case that the 'paddr_len' parameter is passed a null pointer, ...
*
*                       (1) NO input value is saved, ...
*                       (2) NO input value is validated or used.
*********************************************************************************************************
*/
/*$PAGE*/
void  NetConn_AddrLocalGet (NET_CONN_ID         conn_id,
                            CPU_INT08U         *paddr_local,
                            NET_CONN_ADDR_LEN  *paddr_len,
                            NET_ERR            *perr)
{
#if ((NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                    && \
     (NET_CTR_CFG_ERR_EN         == DEF_ENABLED)                    && \
     (CPU_CFG_CRITICAL_METHOD    == CPU_CRITICAL_METHOD_STATUS_LOCAL))
    CPU_SR              cpu_sr;
#endif
#if  (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
    NET_CONN_ADDR_LEN   addr_len;
#endif
    NET_CONN           *pconn;

                                                                /* ------------------ VALIDATE ADDR ------------------- */
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
    if (paddr_len == (NET_CONN_ADDR_LEN *)0) {                  /* See Note #2b.                                        */
        NET_CTR_ERR_INC(NetConn_ErrNullPtrCtr);
       *perr = NET_CONN_ERR_NULL_PTR;
        return;
    }

     addr_len = *paddr_len;                                     /* Save     initial addr len         (see Note #2a1A).  */
#endif
   *paddr_len =  0;                                             /* Cfg      dflt    addr len for err (see Note #2a2).   */

#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
    if (addr_len < NET_CONN_CFG_ADDR_LEN) {                     /* Validate initial addr len         (see Note #2a1B).  */
        NET_CTR_ERR_INC(NetConn_ErrInvalidConnAddrLenCtr);
       *perr = NET_CONN_ERR_INVALID_ADDR_LEN;
        return;
    }
    if (paddr_local == (CPU_INT08U *)0) {
        NET_CTR_ERR_INC(NetConn_ErrNullPtrCtr);
       *perr = NET_CONN_ERR_NULL_PTR;
        return;
    }

                                                                /* -------------- VALIDATE NET CONN USED -------------- */
   (void)NetConn_IsUsed(conn_id, perr);
    if (*perr != NET_CONN_ERR_NONE) {
         return;
    }
#endif


    pconn = &NetConn_Tbl[conn_id];

                                                                /* -------------- VALIDATE NET CONN ADDR -------------- */
    if (pconn->AddrLocalValid != DEF_YES) {                     /* If net conn local addr NOT avail, rtn err.           */
       *perr = NET_CONN_ERR_ADDR_NOT_USED;
        return;
    }


    Mem_Copy((void     *) paddr_local,                          /* Copy & rtn net conn local addr.                      */
             (void     *)&pconn->AddrLocal[0],
             (CPU_SIZE_T) NET_CONN_CFG_ADDR_LEN);

   *paddr_len = NET_CONN_CFG_ADDR_LEN;


   *perr = NET_CONN_ERR_NONE;
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                       NetConn_AddrLocalSet()
*
* Description : Set a network connection's local address.
*
* Argument(s) : conn_id         Handle identifier of network connection to set local address.
*
*               paddr_local     Pointer to local address (see Note #1).
*
*               addr_len        Length  of local address (in octets).
*
*               addr_over_wr    Allow      local address overwrite :
*
*                                   DEF_NO                          Do NOT overwrite local address.
*                                   DEF_YES                                Overwrite local address.
*
*               perr        Pointer to variable that will receive the return error code from this function :
*
*                               NET_CONN_ERR_NONE                   Network connection address successfully set.
*                               NET_CONN_ERR_NULL_PTR               Argument 'paddr_local' passed a NULL
*                                                                       pointer.
*                               NET_CONN_ERR_INVALID_ADDR_LEN       Invalid network connection address length.
*                               NET_CONN_ERR_ADDR_IN_USE            Network connection address already in use.
*
*                                                                   ------ RETURNED BY NetConn_IsUsed() : ------
*                               NET_ERR_INIT_INCOMPLETE             Network initialization NOT complete.
*                               NET_CONN_ERR_INVALID_CONN           Invalid network connection number.
*                               NET_CONN_ERR_NOT_USED               Network connection NOT currently used.
*
* Return(s)   : none.
*
* Caller(s)   : NetSock_BindHandler(),
*               NetTCP_RxPktConnHandlerListen().
*
*               This function is an INTERNAL network protocol suite function & MUST NOT be called by 
*               application function(s).
*
* Note(s)     : (1) Network connection addresses maintained in network-order.
*********************************************************************************************************
*/
/*$PAGE*/
void  NetConn_AddrLocalSet (NET_CONN_ID         conn_id,
                            CPU_INT08U         *paddr_local,
                            NET_CONN_ADDR_LEN   addr_len,
                            CPU_BOOLEAN         addr_over_wr,
                            NET_ERR            *perr)
{
#if ((NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                    && \
     (NET_CTR_CFG_ERR_EN         == DEF_ENABLED)                    && \
     (CPU_CFG_CRITICAL_METHOD    == CPU_CRITICAL_METHOD_STATUS_LOCAL))
    CPU_SR     cpu_sr;
#endif
    NET_CONN  *pconn;


#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                 /* -------------- VALIDATE NET CONN USED -------------- */
   (void)NetConn_IsUsed(conn_id, perr);
    if (*perr != NET_CONN_ERR_NONE) {
         return;
    }
#endif

    pconn = &NetConn_Tbl[conn_id];

#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                 /* ------------------ VALIDATE ADDR ------------------- */
    if (paddr_local == (CPU_INT08U *)0) {
        NET_CTR_ERR_INC(NetConn_ErrNullPtrCtr);
       *perr = NET_CONN_ERR_NULL_PTR;
        return;
    }
    if (addr_len != NET_CONN_CFG_ADDR_LEN) {
        NET_CTR_ERR_INC(NetConn_ErrInvalidConnAddrLenCtr);
       *perr = NET_CONN_ERR_INVALID_ADDR_LEN;
        return;
    }
    if (addr_over_wr != DEF_YES) {                              /* If addr over-wr NOT req'd ...                        */
        if (pconn->AddrLocalValid != DEF_NO) {                  /* ... & local addr valid,   ...                        */
            NET_CTR_ERR_INC(NetConn_ErrInvalidConnAddrInUseCtr);
           *perr = NET_CONN_ERR_ADDR_IN_USE;                    /* ... rtn err.                                         */
            return;
        }
    }

#else                                                           /* Prevent compiler warnings.                           */
   (void)&addr_len;
   (void)&addr_over_wr;
#endif


    Mem_Copy((void     *)&pconn->AddrLocal[0],                  /* Copy local addr to net conn addr.                    */
             (void     *) paddr_local,
             (CPU_SIZE_T) NET_CONN_CFG_ADDR_LEN);

    pconn->AddrLocalValid = DEF_YES;


   *perr = NET_CONN_ERR_NONE;
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                       NetConn_AddrRemoteGet()
*
* Description : Get a network connection's remote address.
*
* Argument(s) : conn_id         Handle identifier of network connection to get remote address.
*
*               paddr_remote    Pointer to variable that will receive the return  remote address (see Note #1),
*                                   if NO errors.
*
*               paddr_len       Pointer to a variable to ... :
*                              
*                                   (a) Pass the size of the address buffer pointed to by 'paddr_remote'.
*                                   (b) Return the actual local address length, if NO errors;
*                                       Return 0,                               otherwise.
*
*                               See also Note #2.
*
*               perr        Pointer to variable that will receive the return error code from this function :
*
*                               NET_CONN_ERR_NONE                   Network connection address get successful.
*                               NET_CONN_ERR_NULL_PTR               Argument 'paddr_local'/'paddr_len'
*                                                                       passed a NULL pointer.
*                               NET_CONN_ERR_INVALID_ADDR_LEN       Invalid network connection address length.
*                               NET_CONN_ERR_ADDR_NOT_USED          Network connection address NOT in use.
*
*                                                                   ----- RETURNED BY NetConn_IsUsed() : -----
*                               NET_ERR_INIT_INCOMPLETE             Network initialization NOT complete.
*                               NET_CONN_ERR_INVALID_CONN           Invalid network connection number.
*                               NET_CONN_ERR_NOT_USED               Network connection NOT currently used.
*
* Return(s)   : none.
*
* Caller(s)   : NetSock_Accept(),
*               NetSock_BindHandler(),
*               NetSock_RxDataHandlerStream(),
*               NetSock_TxDataHandlerDatagram(),
*               NetTCP_TxConnPrepareSegAddrs().
*
*               This function is an INTERNAL network protocol suite function & SHOULD NOT be called by 
*               application function(s).
*
* Note(s)     : (1) Network connection addresses maintained in network-order.
*
*               (2) (a) Since 'paddr_len' parameter is both an input & output parameter (see 'Argument(s) :
*                       paddr_len'), ...
*
*                       (1) its input value, prior to use, MUST be ...
*                           (A) saved, &                           ...
*                           (B) validated;                         ...
*
*                       (2) while its output value MUST be initially configured to return a default error
*                           value in case of any function exit due to error/fault conditions.
*
*                   (b) In the case that the 'paddr_len' parameter is passed a null pointer, ...
*
*                       (1) NO input value is saved, ...
*                       (2) NO input value is validated or used.
*********************************************************************************************************
*/
/*$PAGE*/
void  NetConn_AddrRemoteGet (NET_CONN_ID         conn_id,
                             CPU_INT08U         *paddr_remote,
                             NET_CONN_ADDR_LEN  *paddr_len,
                             NET_ERR            *perr)
{
#if ((NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                    && \
     (NET_CTR_CFG_ERR_EN         == DEF_ENABLED)                    && \
     (CPU_CFG_CRITICAL_METHOD    == CPU_CRITICAL_METHOD_STATUS_LOCAL))
    CPU_SR              cpu_sr;
#endif
#if  (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
    NET_CONN_ADDR_LEN   addr_len;
#endif
    NET_CONN           *pconn;

                                                                /* ------------------ VALIDATE ADDR ------------------- */
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
    if (paddr_len == (NET_CONN_ADDR_LEN *)0) {                  /* See Note #2b.                                        */
        NET_CTR_ERR_INC(NetConn_ErrNullPtrCtr);
       *perr = NET_CONN_ERR_NULL_PTR;
        return;
    }

     addr_len = *paddr_len;                                     /* Save     initial addr len         (see Note #2a1A).  */
#endif
   *paddr_len =  0;                                             /* Cfg      dflt    addr len for err (see Note #2a2).   */

#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
    if (addr_len < NET_CONN_CFG_ADDR_LEN) {                     /* Validate initial addr len         (see Note #2a1B).  */
        NET_CTR_ERR_INC(NetConn_ErrInvalidConnAddrLenCtr);
       *perr = NET_CONN_ERR_INVALID_ADDR_LEN;
        return;
    }
    if (paddr_remote == (CPU_INT08U *)0) {
        NET_CTR_ERR_INC(NetConn_ErrNullPtrCtr);
       *perr = NET_CONN_ERR_NULL_PTR;
        return;
    }

                                                                /* -------------- VALIDATE NET CONN USED -------------- */
   (void)NetConn_IsUsed(conn_id, perr);
    if (*perr != NET_CONN_ERR_NONE) {
         return;
    }
#endif


    pconn = &NetConn_Tbl[conn_id];

                                                                /* -------------- VALIDATE NET CONN ADDR -------------- */
    if (pconn->AddrRemoteValid != DEF_YES) {                    /* If net conn remote addr NOT avail, rtn err.          */
       *perr = NET_CONN_ERR_ADDR_NOT_USED;
        return;
    }


    Mem_Copy((void     *) paddr_remote,                         /* Copy & rtn net conn remote addr.                     */
             (void     *)&pconn->AddrRemote[0],
             (CPU_SIZE_T) NET_CONN_CFG_ADDR_LEN);

   *paddr_len = NET_CONN_CFG_ADDR_LEN;


   *perr = NET_CONN_ERR_NONE;
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                       NetConn_AddrRemoteSet()
*
* Description : Set a network connection's remote address.
*
* Argument(s) : conn_id         Handle identifier of network connection to set remote address.
*
*               paddr_remote    Pointer to remote address (see Note #1).
*
*               addr_len        Length  of remote address (in octets).
*
*               addr_over_wr    Allow      remote address overwrite :
*
*                                   DEF_NO                          Do NOT overwrite remote address.
*                                   DEF_YES                                Overwrite remote address.
*
*               perr        Pointer to variable that will receive the return error code from this function :
*
*                               NET_CONN_ERR_NONE                   Network connection address successfully set.
*                               NET_CONN_ERR_NULL_PTR               Argument 'paddr_local' passed a NULL
*                                                                       pointer.
*                               NET_CONN_ERR_INVALID_ADDR_LEN       Invalid network connection address length.
*                               NET_CONN_ERR_ADDR_IN_USE            Network connection address already in use.
*
*                                                                   ------ RETURNED BY NetConn_IsUsed() : ------
*                               NET_ERR_INIT_INCOMPLETE             Network initialization NOT complete.
*                               NET_CONN_ERR_INVALID_CONN           Invalid network connection number.
*                               NET_CONN_ERR_NOT_USED               Network connection NOT currently used.
*
* Return(s)   : none.
*
* Caller(s)   : NetSock_ConnHandlerAddrRemoteSet(),
*               NetTCP_RxPktConnHandlerListen().
*
*               This function is an INTERNAL network protocol suite function & MUST NOT be called by 
*               application function(s).
*
* Note(s)     : (1) Network connection addresses maintained in network-order.
*********************************************************************************************************
*/
/*$PAGE*/
void  NetConn_AddrRemoteSet (NET_CONN_ID         conn_id,
                             CPU_INT08U         *paddr_remote,
                             NET_CONN_ADDR_LEN   addr_len,
                             CPU_BOOLEAN         addr_over_wr,
                             NET_ERR            *perr)
{
#if ((NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                    && \
     (NET_CTR_CFG_ERR_EN         == DEF_ENABLED)                    && \
     (CPU_CFG_CRITICAL_METHOD    == CPU_CRITICAL_METHOD_STATUS_LOCAL))
    CPU_SR     cpu_sr;
#endif
    NET_CONN  *pconn;


#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                 /* -------------- VALIDATE NET CONN USED -------------- */
   (void)NetConn_IsUsed(conn_id, perr);
    if (*perr != NET_CONN_ERR_NONE) {
         return;
    }
#endif

    pconn = &NetConn_Tbl[conn_id];

#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                 /* ------------------ VALIDATE ADDR ------------------- */
    if (paddr_remote == (CPU_INT08U *)0) {
        NET_CTR_ERR_INC(NetConn_ErrNullPtrCtr);
       *perr = NET_CONN_ERR_NULL_PTR;
        return;
    }
    if (addr_len != NET_CONN_CFG_ADDR_LEN) {
        NET_CTR_ERR_INC(NetConn_ErrInvalidConnAddrLenCtr);
       *perr = NET_CONN_ERR_INVALID_ADDR_LEN;
        return;
    }
    if (addr_over_wr != DEF_YES) {                              /* If addr over-wr NOT req'd ...                        */
        if (pconn->AddrRemoteValid != DEF_NO) {                 /* ... & remote addr valid,  ...                        */
            NET_CTR_ERR_INC(NetConn_ErrInvalidConnAddrInUseCtr);
           *perr = NET_CONN_ERR_ADDR_IN_USE;                    /* ... rtn err.                                         */
            return;
        }
    }

#else                                                           /* Prevent compiler warnings.                           */
   (void)&addr_len;
   (void)&addr_over_wr;
#endif


    Mem_Copy((void     *)&pconn->AddrRemote[0],                 /* Copy remote addr to net conn addr.                   */
             (void     *) paddr_remote,
             (CPU_SIZE_T) NET_CONN_CFG_ADDR_LEN);

    pconn->AddrRemoteValid = DEF_YES;


   *perr = NET_CONN_ERR_NONE;
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                       NetConn_AddrRemoteCmp()
*
* Description : Compare an address to a network connection's remote address.
*
* Argument(s) : conn_id         Handle identifier of connection to compare.
*
*               paddr_remote    Pointer to remote address to compare.
*
*               addr_len        Length  of remote address (in octets).
*
*               perr        Pointer to variable that will receive the return error code from this function :
*
*                               NET_CONN_ERR_NONE                   Remote address successfully compared to 
*                                                                       network connection's remote address;
*                                                                       check return value.
*                               NET_CONN_ERR_NULL_PTR               Argument 'paddr_remote' passed a NULL
*                                                                       pointer.
*                               NET_CONN_ERR_INVALID_ADDR_LEN       Invalid network connection address length.
*                               NET_CONN_ERR_ADDR_NOT_USED          Network connection address NOT in use.
*
*                                                                   ----- RETURNED BY NetConn_IsUsed() : -----
*                               NET_ERR_INIT_INCOMPLETE             Network initialization NOT complete.
*                               NET_CONN_ERR_INVALID_CONN           Invalid network connection number.
*                               NET_CONN_ERR_NOT_USED               Network connection NOT currently used.
*
* Return(s)   : DEF_YES, if addresses successfully compare.
*
*               DEF_NO,  otherwise.
*
* Caller(s)   : NetSock_IsValidAddrRemote().
*
*               This function is an INTERNAL network protocol suite function & SHOULD NOT be called by 
*               application function(s).
*
* Note(s)     : none.
*********************************************************************************************************
*/
/*$PAGE*/
CPU_BOOLEAN  NetConn_AddrRemoteCmp (NET_CONN_ID         conn_id,
                                    CPU_INT08U         *paddr_remote,
                                    NET_CONN_ADDR_LEN   addr_len,
                                    NET_ERR            *perr)
{
#if ((NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                    && \
     (NET_CTR_CFG_ERR_EN         == DEF_ENABLED)                    && \
     (CPU_CFG_CRITICAL_METHOD    == CPU_CRITICAL_METHOD_STATUS_LOCAL))
    CPU_SR        cpu_sr;
#endif
    NET_CONN     *pconn;
    CPU_BOOLEAN   cmp;


#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
                                                                /* -------------- VALIDATE NET CONN USED -------------- */
   (void)NetConn_IsUsed(conn_id, perr);
    if (*perr != NET_CONN_ERR_NONE) {
         return (DEF_NO);
    }

                                                                /* ------------------ VALIDATE ADDR ------------------- */
    if (paddr_remote == (CPU_INT08U *)0) {
        NET_CTR_ERR_INC(NetConn_ErrNullPtrCtr);
       *perr =  NET_CONN_ERR_NULL_PTR;
        return (DEF_NO);
    }
    if (addr_len != NET_CONN_CFG_ADDR_LEN) {
        NET_CTR_ERR_INC(NetConn_ErrInvalidConnAddrLenCtr);
       *perr =  NET_CONN_ERR_INVALID_ADDR_LEN;
        return (DEF_NO);
    }

#else                                                           /* Prevent compiler warning.                            */
   (void)&addr_len;
#endif


    pconn = &NetConn_Tbl[conn_id];

                                                                /* -------------- VALIDATE NET CONN ADDR -------------- */
    if (pconn->AddrRemoteValid != DEF_YES) {                    /* If conn local addr NOT avail, rtn err.               */
       *perr =  NET_CONN_ERR_ADDR_NOT_USED;
        return (DEF_NO);
    }

                                                                
    cmp = Mem_Cmp((void     *) paddr_remote,                    /* Cmp remote addr to conn addr.                        */
                  (void     *)&pconn->AddrRemote[0],
                  (CPU_SIZE_T) NET_CONN_CFG_ADDR_LEN);

   *perr =  NET_CONN_ERR_NONE;

    return (cmp);
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                          NetConn_IsUsed()
*
* Description : Validate network connection in use.
*
* Argument(s) : conn_id     Handle identifier of network connection to validate.
*
*               perr        Pointer to variable that will receive the return error code from this function :
*
*                               NET_CONN_ERR_NONE               Network connection successfully validated
*                                                                   as in use.
*                               NET_ERR_INIT_INCOMPLETE         Network initialization NOT complete.
*                               NET_CONN_ERR_INVALID_CONN       Invalid network connection number.
*                               NET_CONN_ERR_NOT_USED           Network connection NOT currently used.
*
* Return(s)   : DEF_YES, network connection   valid &      in use.
*
*               DEF_NO,  network connection invalid or NOT in use.
*
* Caller(s)   : various.
*
*               This function is an INTERNAL network protocol suite function & SHOULD NOT be called by 
*               application function(s).
*
* Note(s)     : (1) NetConn_IsUsed() blocked until network initialization completes.
*
*               (2) NetConn_IsUsed() MUST be called with the global network lock already acquired.
*********************************************************************************************************
*/

CPU_BOOLEAN  NetConn_IsUsed (NET_CONN_ID   conn_id,
                             NET_ERR      *perr)
{
#if ((NET_CTR_CFG_ERR_EN      == DEF_ENABLED)                    && \
     (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
    CPU_SR        cpu_sr;
#endif
    NET_CONN     *pconn;
    CPU_BOOLEAN   used;


#if (NET_ERR_CFG_ARG_CHK_EXT_EN == DEF_ENABLED)
    if (Net_InitDone != DEF_YES) {                              /* If init NOT complete, exit (see Note #1).            */
       *perr =  NET_ERR_INIT_INCOMPLETE;
        return (DEF_NO);
    }
#endif

                                                                /* --------------- VALIDATE NET CONN ID --------------- */
    if (conn_id < NET_CONN_ID_MIN) {
        NET_CTR_ERR_INC(NetConn_ErrInvalidConnCtr);
       *perr =  NET_CONN_ERR_INVALID_CONN;
        return (DEF_NO);
    }
    if (conn_id > NET_CONN_ID_MAX) {
        NET_CTR_ERR_INC(NetConn_ErrInvalidConnCtr);
       *perr =  NET_CONN_ERR_INVALID_CONN;
        return (DEF_NO);
    }

                                                                /* -------------- VALIDATE NET CONN USED -------------- */
    pconn = &NetConn_Tbl[conn_id];
    used  =  DEF_BIT_IS_SET(pconn->Flags, NET_CONN_FLAG_USED);
    if (used != DEF_YES) {
        NET_CTR_ERR_INC(NetConn_ErrNotUsedCtr);
       *perr =  NET_CONN_ERR_NOT_USED;
        return (DEF_NO);
    }


   *perr =  NET_CONN_ERR_NONE;

    return (DEF_YES);
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                          NetConn_IsConn()
*
* Description : Determine network connection status.
*
* Argument(s) : conn_id     Handle identifier of network connection to check.
*
*               perr        Pointer to variable that will receive the return error code from this function :
*
*                               NET_CONN_ERR_CONN_NONE          NO   network connection.
*                               NET_CONN_ERR_CONN_HALF          Half network connection --
*                                                                   local OR  remote address valid.
*                               NET_CONN_ERR_CONN_FULL          Full network connection --
*                                                                   local AND remote address valid.
*
*                                                               --- RETURNED BY NetConn_IsUsed() : ---
*                               NET_ERR_INIT_INCOMPLETE         Network initialization NOT complete.
*                               NET_CONN_ERR_INVALID_CONN       Invalid network connection number.
*                               NET_CONN_ERR_NOT_USED           Network connection NOT currently used.
*
* Return(s)   : none.
*
* Caller(s)   : various.
*
*               This function is an INTERNAL network protocol suite function & SHOULD NOT be called by 
*               application function(s).
*
* Note(s)     : (1) NetConn_IsConn() MUST be called with the global network lock already acquired.
*********************************************************************************************************
*/

void  NetConn_IsConn (NET_CONN_ID   conn_id,
                      NET_ERR      *perr)
{
    NET_CONN  *pconn;

                                                                /* -------------- VALIDATE NET CONN USED -------------- */
   (void)NetConn_IsUsed(conn_id, perr);
    if (*perr != NET_CONN_ERR_NONE) {
         return;
    }

                                                                /* -------------- DETERMINE CONN STATUS --------------- */
    pconn = &NetConn_Tbl[conn_id];
    if (pconn->AddrLocalValid == DEF_YES) {
        if (pconn->AddrRemoteValid == DEF_YES) {
           *perr = NET_CONN_ERR_CONN_FULL;
        } else {
           *perr = NET_CONN_ERR_CONN_HALF;
        }
    } else {
        if (pconn->AddrRemoteValid == DEF_YES) {
           *perr = NET_CONN_ERR_CONN_HALF;
        } else {
           *perr = NET_CONN_ERR_CONN_NONE;
        }
    }
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                      NetConn_GetConnListType()
*
* Description : Get network connection's current connection list type.
*
* Argument(s) : conn_id     Handle identifier of network connection to check.
*
*               perr        Pointer to variable that will receive the return error code from this function :
*
*                               NET_CONN_ERR_NONE                   Network connection list type successfully
*                                                                       returned; check return value.
*                               NET_CONN_ERR_INVALID_LIST           No current connection list.
*                               NET_CONN_ERR_INVALID_LIST_TYPE      Invalid network connection list type.
*
*                                                                   ---- RETURNED BY NetConn_IsUsed() : -----
*                               NET_ERR_INIT_INCOMPLETE             Network initialization NOT complete.
*                               NET_CONN_ERR_INVALID_CONN           Invalid network connection number.
*                               NET_CONN_ERR_NOT_USED               Network connection NOT currently used.
*
* Return(s)   : Network connection's connection list type, if NO errors.
*
*               NET_CONN_LIST_TYPE_NONE,                   otherwise.
*
* Caller(s)   : various.
*
*               This function is an INTERNAL network protocol suite function & SHOULD NOT be called by 
*               application function(s).
*
* Note(s)     : (1) Default case already invalidated in earlier network connection functions.  However,
*                   the default case is included as an extra precaution in case 'ConnListType' is 
*                   incorrectly modified.
*********************************************************************************************************
*/
/*$PAGE*/
NET_CONN_LIST_TYPE  NetConn_GetConnListType (NET_CONN_ID   conn_id,
                                             NET_ERR      *perr)
{
#if ((NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                    && \
     (NET_CTR_CFG_ERR_EN         == DEF_ENABLED)                    && \
     (CPU_CFG_CRITICAL_METHOD    == CPU_CRITICAL_METHOD_STATUS_LOCAL))
    CPU_SR               cpu_sr;
#endif
    NET_CONN            *pconn;
    NET_CONN_LIST_TYPE   list_type;


#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                 /* ------------- VALIDATE NET CONN USED --------------- */
   (void)NetConn_IsUsed(conn_id, perr);
    if (*perr != NET_CONN_ERR_NONE) {
         return (NET_CONN_LIST_TYPE_NONE);
    }
#endif

    pconn = &NetConn_Tbl[conn_id];

#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                 /* ----------- VALIDATE NET CONN LIST USED ------------ */
    if (pconn->ConnList == (void **)0) {
       *perr =  NET_CONN_ERR_INVALID_LIST;
        return (NET_CONN_LIST_TYPE_NONE);
    }
#endif

                                                                /* ---------- GET NET CONN'S CONN LIST TYPE ----------- */
    list_type = pconn->ConnListType;

#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
    switch (list_type) {
        case NET_CONN_LIST_TYPE_NONE:
        case NET_CONN_LIST_TYPE_SERVER:
        case NET_CONN_LIST_TYPE_CLIENT:
             break;


        default:                                                /* See Note #1.                                         */
             NET_CTR_ERR_INC(NetConn_ErrInvalidListTypeCtr);
            *perr =  NET_CONN_ERR_INVALID_LIST_TYPE;
             return (NET_CONN_LIST_TYPE_NONE);                  /* Prevent 'break NOT reachable' compiler warning.      */
    }
#endif


   *perr =  NET_CONN_ERR_NONE;

    return (list_type);
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                        NetConn_PoolStatGet()
*
* Description : Get network connection statistics pool.
*
* Argument(s) : none.
*
* Return(s)   : Network connection statistics pool, if NO errors.
*
*               NULL               statistics pool, otherwise.
*
* Caller(s)   : Application.
*
*               This function is a network protocol suite application interface (API) function & MAY be 
*               called by application function(s).
*
* Note(s)     : (1) NetConn_PoolStatGet() blocked until network initialization completes; return NULL
*                   statistics pool.
*********************************************************************************************************
*/

NET_STAT_POOL  NetConn_PoolStatGet (void)
{
#if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL)
    CPU_SR         cpu_sr;
#endif
#if (NET_ERR_CFG_ARG_CHK_EXT_EN == DEF_ENABLED)
    NET_ERR        err;
#endif
    NET_STAT_POOL  stat_pool;


#if (NET_ERR_CFG_ARG_CHK_EXT_EN == DEF_ENABLED)
    if (Net_InitDone != DEF_YES) {                              /* If init NOT complete, ...                            */
        NetStat_PoolClr(&stat_pool, &err);
        return (stat_pool);                                     /* ... rtn NULL stat pool (see Note #1).                */
    }
#endif


    CPU_CRITICAL_ENTER();
    stat_pool = NetConn_PoolStat;
    CPU_CRITICAL_EXIT();

    return (stat_pool);
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                   NetConn_PoolStatResetMaxUsed()
*
* Description : Reset network connection statistics pool's maximum number of entries used.
*
* Argument(s) : none.
*
* Return(s)   : none.
*
* Caller(s)   : Application.
*
*               This function is a network protocol suite application interface (API) function & MAY be 
*               called by application function(s).
*
* Note(s)     : none.
*********************************************************************************************************
*/

void  NetConn_PoolStatResetMaxUsed (void)
{
    NET_ERR  err;


    NetStat_PoolResetUsedMax(&NetConn_PoolStat, &err);
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                           NetConn_Srch()
*
* Description : (1) Search connection lists for network connection with specific local & remote addresses :
*
*                   (a) Get    network connection list table index
*                   (b) Search network connection lists :                                   See Note #2
*                       (1) Search with specified search addresses
*                           (A) Search server connection list first
*                           (B) Search client connection list second
*                       (2) Search with wildcard  search address(s), if available
*                           (A) Search server connection list first
*                           (B) Search client connection list second
*                   (c) Return network connection handle identifier, if network connection     found
*                         OR
*                       Null identifier & error code,                if network connection NOT found
*
*               (2) Network connection searches are resolved in order :
*
*                   (a) From greatest number of identical connection address fields to
*                            least    number of identical connection address fields.
*
*                   (b) (1) Server network connection lists first;
*                       (2) Client network connection lists second.
*
*
* Argument(s) : family                  Network connection family type.
*
*               protocol_ix             Network connection list protocol index.
*
*               conn_list_type          Network connection list type :
*
*                                           NET_CONN_LIST_TYPE_ALL          Search ALL    connection lists.
*                                           NET_CONN_LIST_TYPE_SERVER       Search Server Connection List ONLY.
*                                           NET_CONN_LIST_TYPE_CLIENT       Search Client Connection List ONLY.
*
*               sec_srch_addr_reqd      Indicate whether secondary search address is required.
*
*               paddr_local             Pointer to local  address (see Note #3).
*
*               paddr_remote            Pointer to remote address (see Note #3).
*
*               addr_len                Length  of search addresses (in octets).
*
*               pconn_id_transport      Pointer to variable that will receive the returned network
*                                           connection's transport   handle identifier.
*
*               pconn_id_app            Pointer to variable that will receive the returned network
*                                           connection's application handle identifier.
*
* Return(s)   : Handle identifier of network connection with specific local & remote address, if found.
*
*               NET_CONN_ID_NONE,                                                             otherwise.
*
* Caller(s)   : NetSock_RxPktDemux(),
*               NetSock_BindHandler(),
*               NetSock_ConnHandlerAddrRemoteValidate().
*
*               This function is an INTERNAL network protocol suite function & SHOULD NOT be called by 
*               application function(s).
*
* Note(s)     : (3) Network connection addresses maintained in network-order.
*********************************************************************************************************
*/

NET_CONN_ID  NetConn_Srch (NET_CONN_FAMILY      family,
                           NET_CONN_LIST_IX     protocol_ix,
                           NET_CONN_LIST_TYPE   conn_list_type,
                           CPU_BOOLEAN          sec_srch_addr_reqd,
                           CPU_INT08U          *paddr_local,
                           CPU_INT08U          *paddr_remote,
                           NET_CONN_ADDR_LEN    addr_len,
                           NET_CONN_ID         *pconn_id_transport,
                           NET_CONN_ID         *pconn_id_app)
{
#if ((NET_CTR_CFG_ERR_EN      == DEF_ENABLED)                    && \
     (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
    CPU_SR         cpu_sr;
#endif
    NET_CONN     **pconn_list;
    NET_CONN      *pconn;
    NET_CONN_ID    conn_id;
    CPU_INT08U     addr_wildcard[NET_CONN_CFG_ADDR_LEN];


/*$PAGE*/
                                                                /* Init conn id's for err or NOT found srch's.          */
    if (pconn_id_transport != (NET_CONN_ID *)0) {
       *pconn_id_transport  =  NET_CONN_ID_NONE;
    }
    if (pconn_id_app       != (NET_CONN_ID *)0) {
       *pconn_id_app        =  NET_CONN_ID_NONE;
    }



#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
                                                                /* ----------- VALIDATE NET CONN LIST TYPE ------------ */
    switch (conn_list_type) {
        case NET_CONN_LIST_TYPE_ALL:
        case NET_CONN_LIST_TYPE_SERVER:
        case NET_CONN_LIST_TYPE_CLIENT:
             break;


        default:
             NET_CTR_ERR_INC(NetConn_ErrInvalidListTypeCtr);
             return (NET_CONN_ID_NONE);                         /* Prevent 'break NOT reachable' compiler warning.      */
    }

                                                                /* ---------------- VALIDATE ADDR LEN ----------------- */
    if (addr_len != NET_CONN_CFG_ADDR_LEN) {
        NET_CTR_ERR_INC(NetConn_ErrInvalidConnAddrLenCtr);
        return (NET_CONN_ID_NONE);
    }
#else
   (void)&addr_len;                                             /* Prevent compiler warning.                            */
#endif


                                                                /* ------ VALIDATE/CFG CONN LIST FAMILY/PROTOCOL ------ */
    switch (family) {
#if (NET_CONN_CFG_FAMILY == NET_CONN_FAMILY_IP_V4_SOCK)
        case NET_CONN_FAMILY_IP_V4_SOCK:
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
             switch (protocol_ix) {
                 case NET_CONN_LIST_IX_IP_V4_SOCK_UDP:
#ifdef  NET_TCP_MODULE_PRESENT
                 case NET_CONN_LIST_IX_IP_V4_SOCK_TCP:
#endif
                      break;


                 default:
                      NET_CTR_ERR_INC(NetConn_ErrInvalidListIxCtr);
                      return (NET_CONN_ID_NONE);                /* Prevent 'break NOT reachable' compiler warning.      */
             }
#endif

             if (NetConn_AddrWildCardAvail == DEF_YES) {        /* Cfg wildcard addr.                                   */
                 if (paddr_local != (CPU_INT08U *)0) {
                     Mem_Copy((void     *)&addr_wildcard[0],
                              (void     *)paddr_local,
                              (CPU_SIZE_T) NET_CONN_CFG_ADDR_LEN);
                 } else {                                       /* If local addr NOT avail, clr wildcard addr.          */
                     Mem_Clr ((void     *)&addr_wildcard[0],
                              (CPU_SIZE_T) NET_CONN_CFG_ADDR_LEN);
                 }

                 Mem_Copy((void     *)&addr_wildcard[NET_CONN_ADDR_IP_IX_ADDR],
                          (void     *)&NetConn_AddrWildCard[0],
                          (CPU_SIZE_T) NET_CONN_ADDR_IP_LEN_ADDR);
             }
             break;
#endif

        case NET_CONN_FAMILY_NONE:
        default:
             NET_CTR_ERR_INC(NetConn_ErrInvalidFamilyCtr);
             return (NET_CONN_ID_NONE);                         /* Prevent 'break NOT reachable' compiler warning.      */
    }
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
    if (protocol_ix >= NET_CONN_CFG_PROTOCOL_MAX) {
        NET_CTR_ERR_INC(NetConn_ErrInvalidListIxCtr);
        return (NET_CONN_ID_NONE);
    }
#endif


/*$PAGE*/
                                                                /* --------------- SRCH NET CONN LISTS ---------------- */
                                                                /* ------ SRCH CONN LISTS WITH SPECIFIED ADDR(S) ------ */
    if ((conn_list_type == NET_CONN_LIST_TYPE_ALL   ) ||
        (conn_list_type == NET_CONN_LIST_TYPE_SERVER)) {        /* Srch server conn list with req'd addrs.              */

        pconn_list = &NetConn_ServerConnListHead[protocol_ix];
        pconn      =  NetConn_ListSrch((NET_CONN        **)pconn_list,
                                       (NET_CONN_LIST_TYPE)NET_CONN_LIST_TYPE_SERVER,
                                       (CPU_BOOLEAN       )sec_srch_addr_reqd,
                                       (CPU_INT08U       *)paddr_local,
                                       (CPU_INT08U       *)paddr_remote);
        if (pconn != (NET_CONN *)0) {                           /* If net conn found, rtn conn id's.                    */
            if (pconn_id_transport != (NET_CONN_ID *)0) {
               *pconn_id_transport  =  pconn->ID_Transport;
            }
            if (pconn_id_app       != (NET_CONN_ID *)0) {
               *pconn_id_app        =  pconn->ID_App;
            }
            conn_id = pconn->ID;
            return (conn_id);
        }
    }

    if ((conn_list_type == NET_CONN_LIST_TYPE_ALL   ) ||
        (conn_list_type == NET_CONN_LIST_TYPE_CLIENT)) {        /* Srch client conn list with req'd addrs.              */

        pconn_list = &NetConn_ClientConnListHead[protocol_ix];
        pconn      =  NetConn_ListSrch((NET_CONN        **)pconn_list,
                                       (NET_CONN_LIST_TYPE)NET_CONN_LIST_TYPE_CLIENT,
                                       (CPU_BOOLEAN       )sec_srch_addr_reqd,
                                       (CPU_INT08U       *)paddr_local,
                                       (CPU_INT08U       *)paddr_remote);
        if (pconn != (NET_CONN *)0) {                           /* If net conn found, rtn conn id's.                    */
            if (pconn_id_transport != (NET_CONN_ID *)0) {
               *pconn_id_transport  =  pconn->ID_Transport;
            }
            if (pconn_id_app       != (NET_CONN_ID *)0) {
               *pconn_id_app        =  pconn->ID_App;
            }
            conn_id = pconn->ID;
            return (conn_id);
        }
    }

/*$PAGE*/
                                                                /* -------- SRCH CONN LISTS WITH WILDCARD ADDR -------- */
    if (NetConn_AddrWildCardAvail == DEF_YES) {
        if ((conn_list_type == NET_CONN_LIST_TYPE_ALL   ) ||
            (conn_list_type == NET_CONN_LIST_TYPE_SERVER)) {    /* Srch server conn list with wildcard addr.            */

            pconn_list = &NetConn_ServerConnListHead[protocol_ix];
            pconn      =  NetConn_ListSrch((NET_CONN        **) pconn_list,
                                           (NET_CONN_LIST_TYPE) NET_CONN_LIST_TYPE_SERVER,
                                           (CPU_BOOLEAN       ) sec_srch_addr_reqd,
                                           (CPU_INT08U       *)&addr_wildcard[0],
                                           (CPU_INT08U       *)paddr_remote);
            if (pconn != (NET_CONN *)0) {                       /* If net conn found, rtn conn id's.                    */
                if (pconn_id_transport != (NET_CONN_ID *)0) {
                   *pconn_id_transport  =  pconn->ID_Transport;
                }
                if (pconn_id_app       != (NET_CONN_ID *)0) {
                   *pconn_id_app        =  pconn->ID_App;
                }
                conn_id = pconn->ID;
                return (conn_id);
            }
        }

        if ((conn_list_type == NET_CONN_LIST_TYPE_ALL   ) ||
            (conn_list_type == NET_CONN_LIST_TYPE_CLIENT)) {    /* Srch client conn list with wildcard addr.            */
                                                                
            pconn_list = &NetConn_ClientConnListHead[protocol_ix];
            pconn      =  NetConn_ListSrch((NET_CONN        **) pconn_list,
                                           (NET_CONN_LIST_TYPE) NET_CONN_LIST_TYPE_CLIENT,
                                           (CPU_BOOLEAN       ) sec_srch_addr_reqd,
                                           (CPU_INT08U       *)&addr_wildcard[0],
                                           (CPU_INT08U       *)paddr_remote);
            if (pconn != (NET_CONN *)0) {                       /* If net conn found, rtn conn id's.                    */
                if (pconn_id_transport != (NET_CONN_ID *)0) {
                   *pconn_id_transport  =  pconn->ID_Transport;
                }
                if (pconn_id_app       != (NET_CONN_ID *)0) {
                   *pconn_id_app        =  pconn->ID_App;
                }
                conn_id = pconn->ID;
                return (conn_id);
            }
        }
    }


    return (NET_CONN_ID_NONE);                                  /* NO net conn found.                                   */
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                          NetConn_ListAdd()
*
* Description : (1) Add a network connection into a connection list :
*
*                   (a) Get network connection's appropriate connection list
*                   (b) Get network connection's appropriate connection chain
*                   (c) Add network connection into          connection list
*
*
* Argument(s) : conn_id             Handle identifier of network connection to add.
*
*               conn_list_type      Network connection list type :
*
*                                       NET_CONN_LIST_TYPE_SERVER       Connection list organized primarily
*                                                                           by local  address.
*                                       NET_CONN_LIST_TYPE_CLIENT       Connection list organized primarily
*                                                                           by remote address.
*
*               perr        Pointer to variable that will receive the return error code from this function :
*
*                               NET_CONN_ERR_NONE                   Network connection successfully
*                                                                       added to connection list.
*                               NET_CONN_ERR_INVALID_FAMILY         Invalid network connection family.
*                               NET_CONN_ERR_INVALID_LIST_TYPE      Invalid network connection list type.
*                               NET_CONN_ERR_INVALID_LIST_IX        Invalid network connection list index.
*
*                                                                   --- RETURNED BY NetConn_IsUsed() : ---
*                               NET_ERR_INIT_INCOMPLETE             Network initialization NOT complete.
*                               NET_CONN_ERR_INVALID_CONN           Invalid network connection number.
*                               NET_CONN_ERR_NOT_USED               Network connection NOT currently used.
*
* Return(s)   : none.
*
* Caller(s)   : NetSock_BindHandler(),
*               NetSock_ConnHandlerDatagram(),
*               NetSock_ConnHandlerStream(),
*               NetTCP_RxPktConnHandlerListen().
*
*               This function is an INTERNAL network protocol suite function & MUST NOT be called by 
*               application function(s).
*
* Note(s)     : (2) Network connection addresses maintained in network-order.
*
*               (3) Local &/or remote addresses SHOULD be set prior to network connection list add.
*
*               (4) #### Search for connection list chain ONLY performed if connection's remote address
*                   is available.  However, this assumes ALL connections have unique local addresses.
*
*                   #### If local addresses are NOT necessarily unique, should connection list chain
*                   always be searched?
*********************************************************************************************************
*/
/*$PAGE*/
void  NetConn_ListAdd (NET_CONN_ID          conn_id,
                       NET_CONN_LIST_TYPE   conn_list_type,
                       NET_ERR             *perr)
{
#if ((NET_CTR_CFG_ERR_EN      == DEF_ENABLED)                    && \
     (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
    CPU_SR              cpu_sr;
#endif
    NET_CONN           *pconn;
    NET_CONN           *pconn_chain;
    NET_CONN          **pconn_list;
    NET_CONN_LIST_IX    protocol_ix;
    CPU_INT08U          addr_wildcard[NET_CONN_CFG_ADDR_LEN];


#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                 /* -------------- VALIDATE NET CONN USED -------------- */
   (void)NetConn_IsUsed(conn_id, perr);
    if (*perr != NET_CONN_ERR_NONE) {
         return;
    }
#endif

    pconn = &NetConn_Tbl[conn_id];
                                                                /* ------ VALIDATE/CFG CONN LIST FAMILY/PROTOCOL ------ */
    switch (pconn->Family) {
#if (NET_CONN_CFG_FAMILY == NET_CONN_FAMILY_IP_V4_SOCK)
        case NET_CONN_FAMILY_IP_V4_SOCK:
             if (NetConn_AddrWildCardAvail == DEF_YES) {        /* Cfg wildcard addr.                                   */
                 if (pconn->AddrLocalValid == DEF_YES) {
                     Mem_Copy((void     *)&addr_wildcard[0],
                              (void     *)&pconn->AddrLocal[0],
                              (CPU_SIZE_T) NET_CONN_CFG_ADDR_LEN);
                 } else {
                     Mem_Clr ((void     *)&addr_wildcard[0],
                              (CPU_SIZE_T) NET_CONN_CFG_ADDR_LEN);
                 }

                 Mem_Copy((void     *)&addr_wildcard[NET_CONN_ADDR_IP_IX_ADDR],
                          (void     *)&NetConn_AddrWildCard[0],
                          (CPU_SIZE_T) NET_CONN_ADDR_IP_LEN_ADDR);
             }
             break;
#endif

        case NET_CONN_FAMILY_NONE:
        default:
             NET_CTR_ERR_INC(NetConn_ErrInvalidFamilyCtr);
            *perr = NET_CONN_ERR_INVALID_FAMILY;
             return;                                            /* Prevent 'break NOT reachable' compiler warning.      */
    }


/*$PAGE*/
                                                                /* ---------------- GET NET CONN LIST ----------------- */
    protocol_ix = pconn->ProtocolListIx;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
    if (protocol_ix >= NET_CONN_CFG_PROTOCOL_MAX) {
        NET_CTR_ERR_INC(NetConn_ErrInvalidListIxCtr);
       *perr = NET_CONN_ERR_INVALID_LIST_IX;
        return;
    }
#endif

    switch (conn_list_type) {
        case NET_CONN_LIST_TYPE_SERVER:
             pconn_list = &NetConn_ServerConnListHead[protocol_ix];
             break;


        case NET_CONN_LIST_TYPE_CLIENT:
             pconn_list = &NetConn_ClientConnListHead[protocol_ix];
             break;


        case NET_CONN_LIST_TYPE_NONE:
        default:
             NET_CTR_ERR_INC(NetConn_ErrInvalidListTypeCtr);
            *perr = NET_CONN_ERR_INVALID_LIST_TYPE;
             return;                                            /* Prevent 'break NOT reachable' compiler warning.      */
    }


                                                                /* ---------- GET NET CONN'S CONN LIST CHAIN ---------- */
    if (pconn->AddrRemoteValid == DEF_YES) {                    /* If remote addr avail, ...                            */
                                                                /* ... srch conn list for conn chain (see Note #4).     */
        pconn_chain = NetConn_ListSrch((NET_CONN        **) pconn_list,
                                       (NET_CONN_LIST_TYPE) conn_list_type,
                                       (CPU_BOOLEAN       ) DEF_NO,
                                       (CPU_INT08U       *)&pconn->AddrLocal[0],
                                       (CPU_INT08U       *)&pconn->AddrRemote[0]);

        if (pconn_chain == (NET_CONN *)0) {                     /* If specified local addr conn chain NOT found, ...    */
            if (NetConn_AddrWildCardAvail == DEF_YES) {         /* ... srch conn list with wildcard addr.               */
                pconn_chain = NetConn_ListSrch((NET_CONN        **) pconn_list,
                                               (NET_CONN_LIST_TYPE) conn_list_type,
                                               (CPU_BOOLEAN       ) DEF_NO,
                                               (CPU_INT08U       *)&addr_wildcard[0],
                                               (CPU_INT08U       *)&pconn->AddrRemote[0]);
            }
        }
        
    } else {
        pconn_chain = (NET_CONN *)0;
    }


                                                                /* --------- ADD NET CONN INTO NET CONN LIST ---------- */
    NetConn_Add(pconn_list,
                pconn_chain,
                pconn,
                conn_list_type);


   *perr = NET_CONN_ERR_NONE;
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                        NetConn_ListUnlink()
*
* Description : Unlink a network connection from a connection list.
*
* Argument(s) : conn_id     Handle identifier of network connection to unlink.
*
*               perr        Pointer to variable that will receive the return error code from this function :
*
*                               NET_CONN_ERR_NONE               Network connection successfully unlinked
*                                                                   from connection list.
*
*                                                               ---- RETURNED BY NetConn_IsUsed() : ----
*                               NET_ERR_INIT_INCOMPLETE         Network initialization NOT complete.
*                               NET_CONN_ERR_INVALID_CONN       Invalid network connection number.
*                               NET_CONN_ERR_NOT_USED           Network connection NOT currently used.
*
* Return(s)   : none.
*
* Caller(s)   : NetSock_BindHandler(),
*               NetSock_ConnHandlerDatagram(),
*               NetSock_ConnHandlerStream().
*
*               This function is an INTERNAL network protocol suite function & MUST NOT be called by 
*               application function(s).
*
* Note(s)     : none.
*********************************************************************************************************
*/

void  NetConn_ListUnlink (NET_CONN_ID   conn_id,
                          NET_ERR      *perr)
{
    NET_CONN  *pconn;


#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                 /* -------------- VALIDATE NET CONN USED -------------- */
   (void)NetConn_IsUsed(conn_id, perr);
    if (*perr != NET_CONN_ERR_NONE) {
         return;
    }
#endif

                                                                /* -------- UNLINK NET CONN FROM NET CONN LIST -------- */
    pconn = &NetConn_Tbl[conn_id];
    NetConn_Unlink(pconn);


   *perr = NET_CONN_ERR_NONE;
}


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

/*
*********************************************************************************************************
*                                           NetConn_Close()
*
* Description : (1) Close a network connection :
*
*                   (a) Update network connection close statistic(s)
*
*                   (b) Close  network connection(s) :
*                       (1) Close application connection
*                       (2) Close transport   connection
*
*                   (c) Free   network connection, if necessary
*
*
* Argument(s) : pconn       Pointer to a network connection.
*               -----       Argument checked in NetConn_CloseAllConnListConns(),
*                                               NetConn_ListValidateConn().
*
* Return(s)   : none.
*
* Caller(s)   : NetConn_CloseAllConnListConns(),
*               NetConn_ListValidateConn().
*
* Note(s)     : (2) Network connection's handle identifier MUST be obtained PRIOR to any network 
*                   connection validation &/or close operations.
*
*               (3) (a) Network connection(s) MAY  already be closed BEFORE any  network connection 
*                       close operations & MUST be validated as used BEFORE each network connection 
*                       close operation.
*
*                   (b) Network connection SHOULD already be closed AFTER application & transport 
*                       layer connections have both closed.
*
*                       See also 'NetConn_CloseFromApp()        Note #1c'
*                              & 'NetConn_CloseFromTransport()  Note #1c'.
*********************************************************************************************************
*/

static  void  NetConn_Close (NET_CONN  *pconn)
{
#if ((NET_CTR_CFG_ERR_EN      == DEF_ENABLED)                    && \
     (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
    CPU_SR       cpu_sr;
#endif
    NET_CONN_ID  conn_id;
    NET_ERR      err;
    CPU_BOOLEAN  used;

                                                                /* --------------- UPDATE CLOSE STATS ----------------- */
    NET_CTR_ERR_INC(NetConn_ErrCloseCtr);

                                                                /* ------------------ CLOSE CONN(S) ------------------- */
    conn_id = pconn->ID;                                        /* Get net conn id (see Note #2).                       */

    used = NetConn_IsUsed(conn_id, &err);
    if (used == DEF_YES) {                                      /* If net conn used (see Note #3a), ...                 */
        NetConn_CloseApp(pconn);                                /* ... close app conn.                                  */
    }

    used = NetConn_IsUsed(conn_id, &err);
    if (used == DEF_YES) {                                      /* If net conn used (see Note #3a), ...                 */
        NetConn_CloseTransport(pconn);                          /* ... close transport conn.                            */
    }


#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                 /* ------------------ FREE NET CONN ------------------- */
    used = NetConn_IsUsed(conn_id, &err);
    if (used == DEF_YES) {                                      /* If net conn used (see Note #3b), ...                 */
        NetConn_FreeHandler(pconn);                             /* ... free net conn.                                   */
    }
#endif
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                         NetConn_CloseApp()
*
* Description : (1) Close a network connection's application connection :
*
*                   (a) Free  network     connection from application clone connection, if necessary
*                   (b) Close application connection
*
*
* Argument(s) : pconn       Pointer to a network connection.
*               -----       Argument validated in NetConn_Close(),
*                                                 NetConn_CloseFromTransport().
*
* Return(s)   : none.
*
* Caller(s)   : NetConn_Close(),
*               NetConn_CloseFromTransport().
*
* Note(s)     : (2) The 'NET_CONN_CFG_FAMILY' pre-processor 'else'-conditional code will never be compiled/linked
*                   since 'net_conn.h' ensures that the family type configuration constant (NET_CONN_CFG_FAMILY)
*                   is configured with an appropriate family type value (see 'net_conn.h  CONFIGURATION ERRORS').
*                   The 'else'-conditional code is included for completeness & as an extra precaution in case
*                   'net_conn.h' is incorrectly modified.
*********************************************************************************************************
*/

static  void  NetConn_CloseApp (NET_CONN  *pconn)
{
                                                                /* ---------------- CLOSE APP CONN(S) ----------------- */
#if (NET_CONN_CFG_FAMILY == NET_CONN_FAMILY_IP_V4_SOCK)         
    NetSock_FreeConnFromSock((NET_SOCK_ID)pconn->ID_AppClone,   /* Free net conn from clone sock conn (see Note #1a).   */
                             (NET_CONN_ID)pconn->ID);    

    NetSock_CloseFromConn((NET_SOCK_ID)pconn->ID_App);          /* Close sock app conn (see Note #1b).                  */

#else                                                           /* See Note #2.                                         */
   (void)&pconn;                                                /* Prevent compiler warning.                            */
#endif
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                      NetConn_CloseTransport()
*
* Description : Close a network connection's transport connection.
*
* Argument(s) : pconn       Pointer to a network connection.
*               -----       Argument validated in NetConn_Close(),
*                                                 NetConn_CloseFromApp().
*
* Return(s)   : none.
*
* Caller(s)   : NetConn_Close(),
*               NetConn_CloseFromApp().
*
* Note(s)     : (1) The 'NET_CONN_CFG_FAMILY' pre-processor 'else'-conditional code will never be compiled/linked
*                   since 'net_conn.h' ensures that the family type configuration constant (NET_CONN_CFG_FAMILY)
*                   is configured with an appropriate family type value (see 'net_conn.h  CONFIGURATION ERRORS').
*                   The 'else'-conditional code is included for completeness & as an extra precaution in case
*                   'net_conn.h' is incorrectly modified.
*********************************************************************************************************
*/

static  void  NetConn_CloseTransport (NET_CONN  *pconn)
{
                                                                /* --------------- CLOSE TRANSPORT CONN -------------- */
#if    (NET_CONN_CFG_FAMILY == NET_CONN_FAMILY_IP_V4_SOCK)
#ifdef  NET_TCP_MODULE_PRESENT
    NetTCP_ConnCloseFromConn((NET_TCP_CONN_ID)pconn->ID_Transport);
#endif

#else                                                           /* See Note #1.                                         */
   (void)&pconn;                                                /* Prevent compiler warning.                            */
#endif
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                   NetConn_CloseAllConnListConns()
*
* Description : Close ALL network connections in a network connection list.
*
* Argument(s) : pconn_list      Pointer to a network connection list.
*               ----------      Argument validated in NetConn_CloseAllConnsHandler().
*
* Return(s)   : none.
*
* Caller(s)   : NetConn_CloseAllConnsHandler().
*
* Note(s)     : (1) Invalid network connection(s) in the connection list MAY already be closed in other
*                   validation functions.
*
*                   See also 'NetConn_ListValidateConn()  Note #3'.
*
*               (2) Since network connection close handlers execute asynchronously to NetConn_FreeHandler(),
*                   network connection list pointers ('NetConn_ConnListChainPtr', 'NetConn_ConnListConnPtr',
*                   etc.) MUST be coordinated with NetConn_FreeHandler() to avoid network connection list
*                   corruption :
*
*                   (a) (1) Network connection list pointers typically advance to the next network connection
*                           in a network connection list.
*
*                       (2) However, whenever a network connection list pointer connection is freed by an
*                           asynchronous network connection close, the network connection list pointer(s)
*                           MUST be advanced to the next valid & available network connection in the
*                           network connection list.
*
*                           See also 'NetConn_FreeHandler()  Note #2a'.
*
*                   (b) Network connection list pointers MUST be cleared after handling the network
*                       connection list.
*
*                       (1) However, network connection list pointers are implicitly cleared after 
*                           handling the network connection list.
*********************************************************************************************************
*/

static  void  NetConn_CloseAllConnListConns (NET_CONN  **pconn_list)
{
    NetConn_ConnListChainPtr = (NET_CONN *)*pconn_list;                 /* Start close @ conn list head.                */

    while (NetConn_ConnListChainPtr != (NET_CONN *)0) {                 /* Close ALL net conn chains ...                */
        NetConn_ConnListNextChainPtr = (NET_CONN *)NetConn_ConnListChainPtr->NextChainPtr;
        NetConn_ConnListConnPtr      = (NET_CONN *)NetConn_ConnListChainPtr;

        while (NetConn_ConnListConnPtr != (NET_CONN *)0) {              /* ... & ALL net conns.                         */
            NetConn_ConnListNextConnPtr = (NET_CONN *)NetConn_ConnListConnPtr->NextConnPtr;

            NetConn_Close(NetConn_ConnListConnPtr);                     /* Close net conn.                              */

            NetConn_ConnListConnPtr = NetConn_ConnListNextConnPtr;      /* Adv to next net conn       (see Note #2a1).  */
        }

        NetConn_ConnListChainPtr    = NetConn_ConnListNextChainPtr;     /* Adv to next net conn chain (see Note #2a1).  */
    }


#if  (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                        /* Clr net conn list ptrs (see Note #2b1).      */
    NetConn_ConnListChainPtr     = (NET_CONN *)0;
    NetConn_ConnListConnPtr      = (NET_CONN *)0;
    NetConn_ConnListNextChainPtr = (NET_CONN *)0;
    NetConn_ConnListNextConnPtr  = (NET_CONN *)0;
#endif
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                        NetConn_FreeHandler()
*
* Description : (1) Free a network connection :
*
*                   (a) Remove network connection from a   network connection list :
*                       (1) Update network connection list pointer(s)                       See Note #2
*                       (2) Unlink network connection from network connection list
*
*                   (b) Clear  network connection values
*                   (c) Free   network connection back to network connection pool
*                   (d) Update network connection pool statistics
*
*
* Argument(s) : pconn       Pointer to a network connection.
*               -----       Argument validated in NetConn_Free(),
*                                                 NetConn_Close(),
*                                                 NetConn_CloseFromApp(),
*                                                 NetConn_CloseFromTransport(),
*                                                 NetConn_ListValidateConn().
*
* Return(s)   : none.
*
* Caller(s)   : NetConn_Free(),
*               NetConn_Close(),
*               NetConn_CloseFromApp(),
*               NetConn_CloseFromTransport(),
*               NetConn_ListValidateConn().
*
* Note(s)     : (2) Since network connection close handlers execute asynchronously to NetConn_FreeHandler(),
*                   network connection list pointers ('NetConn_ConnListChainPtr', 'NetConn_ConnListConnPtr',
*                   etc.) MUST be coordinated with NetConn_FreeHandler() to avoid network connection list
*                   corruption :
*
*                   (a) Whenever a network connection list pointer connection is freed, network connection
*                       list pointers MUST be advanced to the next valid & available network connection in
*                       the appropriate network connection list.
*
*                   See also 'NetConn_CloseAllConnListConns()  Note #2'.
*********************************************************************************************************
*/

static  void  NetConn_FreeHandler (NET_CONN  *pconn)
{
#if ((NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                    && \
     (NET_CTR_CFG_ERR_EN         == DEF_ENABLED)                    && \
     (CPU_CFG_CRITICAL_METHOD    == CPU_CRITICAL_METHOD_STATUS_LOCAL))
    CPU_SR     cpu_sr;
#endif
    NET_CONN  *pnext;
    NET_ERR    err;


#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                 /* ------------------ VALIDATE TYPE ------------------- */
    if (pconn->Type != NET_CONN_TYPE_CONN) {
        NetConn_Discard(pconn);
        NET_CTR_ERR_INC(NetConn_ErrInvalidTypeCtr);
        return;
    }
#endif
                                                                /* -------- REMOVE NET CONN FROM NET CONN LIST -------- */
                                                                /* If net conn is next conn list conn to update, ...    */
                                                                /* ... adv to skip this net conn (see Note #2a).        */
    if (pconn == NetConn_ConnListNextChainPtr) {
        pnext                        = (NET_CONN *)NetConn_ConnListNextChainPtr->NextChainPtr;
        NetConn_ConnListNextChainPtr = (NET_CONN *)pnext;
    }
    if (pconn == NetConn_ConnListNextConnPtr) {
        pnext                        = (NET_CONN *)NetConn_ConnListNextConnPtr->NextConnPtr;
        NetConn_ConnListNextConnPtr  = (NET_CONN *)pnext;
    }

    NetConn_Unlink(pconn);                                      /* Unlink net conn from net conn list.                  */


                                                                /* ------------------- CLR NET CONN ------------------- */
    DEF_BIT_CLR(pconn->Flags, NET_CONN_FLAG_USED);              /* Set net conn as NOT used.                            */
#if (NET_DBG_CFG_MEM_CLR_EN == DEF_ENABLED)
    NetConn_Clr(pconn);
#endif

                                                                /* ------------------ FREE NET CONN ------------------- */
    pconn->NextConnPtr = (void     *)NetConn_PoolPtr;
    NetConn_PoolPtr    = (NET_CONN *)pconn;

                                                                /* ------------ UPDATE NET CONN POOL STATS ------------ */
    NetStat_PoolEntryUsedDec(&NetConn_PoolStat, &err);
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                            NetConn_Clr()
*
* Description : Clear network connection controls.
*
* Argument(s) : pconn       Pointer to a network connection.
*               -----       Argument validated in NetConn_Init(),
*                                                 NetConn_Get(),
*                                                 NetConn_FreeHandler().
*
* Return(s)   : none.
*
* Caller(s)   : NetConn_Init(),
*               NetConn_Get(),
*               NetConn_FreeHandler().
*
* Note(s)     : none.
*********************************************************************************************************
*/

static  void  NetConn_Clr (NET_CONN  *pconn)
{
    pconn->PrevChainPtr         = (void  *)0;
    pconn->NextChainPtr         = (void  *)0;
    pconn->PrevConnPtr          = (void  *)0;
    pconn->NextConnPtr          = (void  *)0;
    pconn->ConnList             = (void **)0;
    pconn->Family               =  NET_CONN_FAMILY_NONE;
    pconn->ProtocolListIx       =  NET_CONN_LIST_IX_NONE;
    pconn->ConnListType         =  NET_CONN_LIST_TYPE_NONE;
    pconn->ID_App               =  NET_CONN_ID_NONE;
    pconn->ID_AppClone          =  NET_CONN_ID_NONE;
    pconn->ID_Transport         =  NET_CONN_ID_NONE;
    pconn->AddrLocalValid       =  DEF_NO;
    pconn->AddrRemoteValid      =  DEF_NO;
    pconn->ConnChainAccessedCtr =  0;
    pconn->ConnAccessedCtr      =  0;
    pconn->Flags                =  NET_CONN_FLAG_NONE;

    Mem_Clr((void     *)&pconn->AddrLocal[0],
            (CPU_SIZE_T) NET_CONN_CFG_ADDR_LEN);
    Mem_Clr((void     *)&pconn->AddrRemote[0],
            (CPU_SIZE_T) NET_CONN_CFG_ADDR_LEN);
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                          NetConn_Discard()
*
* Description : (1) Discard an invalid/corrupted network  connection :
*
*                   (a) Discard network connection from available network connection pool       See Note #2
*                   (b) Update  network connection pool statistics
*
*               (2) Assumes network connection is invalid/corrupt & MUST be removed.  Network 
*                   connection removed simply by NOT returning the network connection back to
*                   the network connection pool.
*
*
* Argument(s) : pconn       Pointer to an invalid/corrupted network connection.
*
* Return(s)   : none.
*
* Caller(s)   : NetConn_Get(),
*               NetConn_FreeHandler(),
*               NetConn_ListValidateConn().
*
* Note(s)     : none.
*********************************************************************************************************
*/

#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
static  void  NetConn_Discard (NET_CONN  *pconn)
{
    NET_ERR  stat_err;

                                                                /* ----------------- DISCARD NET CONN ----------------- */
   (void)&pconn;                                                /* Prevent compiler warning (see Note #2).              */

                                                                /* --------------- UPDATE DISCARD STATS --------------- */
    NetStat_PoolEntryLostInc(&NetConn_PoolStat, &stat_err);
}
#endif


/*$PAGE*/
/*
*********************************************************************************************************
*                                         NetConn_ListSrch()
*
* Description : Search a network connection list for network connection with specific local & remote addresses.
*
*               (1) Connections are organized into connection chains to expedite connection searches.
*
*                   (a) For each connection family & protocol type, two connection lists are maintained :
*                       
*                       (1) A server connection list organized primarily by each connection's local  address
*                       (2) A client connection list organized primarily by each connection's remote address
*                       
*                   (b) (1) Each connection list is maintained as a list of connection lists.  Each connection 
*                           list is uniquely organized by one of the connection addresses -- either the local 
*                           or the remote address depending on the connection list type (see Note #1a).
*
*                           In other words, a connection list's top-level connections are each the heads of 
*                           their own connection list & each have a primary address (either local or remote) 
*                           that is unique from all the other connection lists.
*
*                       (2) Each connection list maintained within a connection list is also referred to as
*                           a connection chain.
*
*                   (c) Each connection chain is an organization of connections that all share the same 
*                       primary connection address [either local or remote (see Note #1a)] but different 
*                       secondary addresses.
*
*                       In other words, each connection in a connection chain shares the connection chain's 
*                       primary connection address but has its own unique secondary connection address.
*
*                   (d) Therefore, connections in a connection chain may share the same local OR remote
*                       connection addresses; however, no two connections in a connection chain share
*                       the same local AND remote connection address.
*
*                   (e) In the diagram below, ...
*
*                       (1) The top horizontal row  represents the connection list's list of connection chains.
*
*                       (2) Each    vertical column represents the connections in unique     connection chains.
*
*                       (3) Each connection list is a pointer that points to the head of the connection list.
*
*                       (4) Connections' 'PrevChainPtr' & 'NextChainPtr' doubly-link each connection chain to 
*                           form the list of connection chains.
*
*                       (5) Connections' 'PrevConnPtr'  & 'NextConnPtr'  doubly-link each connection to form a
*                           connection chain.
*
*                   (f) For any connection search, each connection list is searched in order by the primary
*                       address (either local or remote) to find the appropriate connection chain.  If a
*                       connection chain with the primary search address is found, then each connection in
*                       the connection chain is searched in order to find the connection with the secondary
*                       search address.
*
*                   (g) To expedite faster connection searches for recently added network connections :
*
*                       (1) New network connection chains are added at the head of a network connection list.
*
*                       (2) New network connections are added at or immediately following the head of a network 
*                           connection chain :
*
*                           (A) New connections in a server connection list are added ...
*
*                               (1) As the second connection immediately following the connection chain head,
*                                   if the connection chain head connection is an unconnected server connection
*                                   (i.e. no remote connection address is available).
*
*                               (2) At the head of a connection chain, if the current connection chain head is 
*                                   NOT an unconnected server connection.
*
*                           (B) New network connections in a client connection list are added at the head of a 
*                               network connection chain.
*
*                       See also 'NetConn_Add()  Note #1'.
*$PAGE*
*
*                                            |                                                             |
*                                            |<---------------- List of Connection Chains ---------------->|
*                                            |                      (see Note #1e1)                        |
*
*                                New connection chains inserted
*                                  at head of connection list
*                                       (see Note #1g1)
*
*                                               |              NextChainPtr
*                                               |             (see Note #1e4)
*                                               v                    |
*                                                                    |
*                           Head of          -------       -------   v   -------       -------       -------
*                       Connection List ---->|     |------>|     |------>|     |------>|     |------>|     |
*                                            |     |       |     |       |     |       |     |       |     |
*                       (see Note #1e3)      |     |<------|     |<------|     |<------|     |<------|     |
*                                            -------       -------   ^   -------       -------       -------
*                                              | ^                   |                   | ^
*                                              | |                   |                   | |
*                                              v |             PrevChainPtr              v |
*               ---                          -------          (see Note #1e4)          -------
*                ^                           |     |                                   |     |
*                |                           |     |                                   |     |
*                |                           |     |                                   |     |
*                |                           -------                                   -------
*                |                             | ^                                       | ^
*                |           NextConnPtr ----> | |                                       | | <----  PrevConnPtr
*                |         (see Note #1e5)     v |                                       v |      (see Note #1e5)
*                                            -------                                   -------
*      Connections organized                 |     |                                   |     |
*     into a connection chain                |     |                                   |     |
*         (see Note #1e2)                    |     |                                   |     |
*                                            -------                                   -------
*                |                             | ^
*                |                             | |
*                |                             v |
*                |                           -------
*                |                           |     |
*                |                           |     |
*                v                           |     |
*               ---                          -------
*
*
* Argument(s) : pconn_list              Pointer to a connection list.
*               ----------              Argument validated in NetConn_Srch().
*
*               conn_list_type          Network connection list type :
*
*                                           NET_CONN_LIST_TYPE_SERVER       Connection list organized primarily
*                                                                               by local  address.
*                                           NET_CONN_LIST_TYPE_CLIENT       Connection list organized primarily
*                                                                               by remote address.
*
*               sec_srch_addr_reqd      Indicate whether secondary search address is required.
*
*               paddr_local             Pointer to local  address (see Note #2).
*
*               paddr_remote            Pointer to remote address (see Note #2).
*
* Return(s)   : Pointer to connection with specific local & remote address, if found.
*
*               Pointer to NULL,                                            otherwise.
*
* Caller(s)   : NetConn_Srch().
*
* Note(s)     : (2) Network connection addresses maintained in network-order.
*
*               (3) (a) Assumes ALL connections' local   address is valid.
*
*                   (b) Assumes ALL connections' primary address is valid; i.e. for connections on server
*                       connection lists, the connections' remote addresses are assumed to be valid.
*
*               (4) Default case already invalidated in NetConn_Srch().  However, the default case is
*                   included as an extra precaution in case 'conn_list_type' is corrupted.
*********************************************************************************************************
*/
/*$PAGE*/
static  NET_CONN  *NetConn_ListSrch (NET_CONN            **pconn_list,
                                     NET_CONN_LIST_TYPE    conn_list_type,
                                     CPU_BOOLEAN           sec_srch_addr_reqd,
                                     CPU_INT08U           *paddr_local,
                                     CPU_INT08U           *paddr_remote)
{
#if ((NET_CTR_CFG_ERR_EN      == DEF_ENABLED)                    && \
     (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
    CPU_SR        cpu_sr;
#endif
    NET_CONN     *pconn;
    NET_CONN     *pconn_next;
    NET_CONN     *pconn_chain;
    NET_CONN     *pconn_chain_next;
    CPU_INT08U   *pconn_addr_local;
    CPU_INT08U   *pconn_addr_remote;
    CPU_BOOLEAN   found;
    CPU_BOOLEAN   found_prim_addr;


#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)                 /* -------------- VALIDATE SRCH REQ OPT --------------- */
    switch (sec_srch_addr_reqd) {
        case DEF_NO:
        case DEF_YES:
             break;


        default:
             sec_srch_addr_reqd = DEF_YES;
             break;
    }
#endif

                                                                /* ---------- VALIDATE CONN LIST TYPE / PTRS ---------- */
    switch (conn_list_type) {
        case NET_CONN_LIST_TYPE_SERVER:
             if (paddr_local == (CPU_INT08U *)0) {
                 return ((NET_CONN *)0);
             }

#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
             if (sec_srch_addr_reqd == DEF_YES) {               /* If conn sec  addr req'd,   ...                       */
                 if (paddr_remote == (CPU_INT08U *)0) {         /* ... & remote addr ptr NULL ...                       */
                     NET_CTR_ERR_INC(NetConn_ErrNullPtrCtr);
                     return ((NET_CONN *)0);                    /* ... rtn NULL.                                        */
                 }
             }
#endif
             break;


        case NET_CONN_LIST_TYPE_CLIENT:
             if (paddr_remote == (CPU_INT08U *)0) {
                 return ((NET_CONN *)0);
             }

#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
             if (sec_srch_addr_reqd == DEF_YES) {               /* If conn sec  addr req'd,   ...                       */
                 if (paddr_local == (CPU_INT08U *)0) {          /* ... & local  addr ptr NULL ...                       */
                     NET_CTR_ERR_INC(NetConn_ErrNullPtrCtr);
                     return ((NET_CONN *)0);                    /* ... rtn NULL.                                        */
                 }
             }
#endif
             break;


        case NET_CONN_LIST_TYPE_NONE:
        default:
             NET_CTR_ERR_INC(NetConn_ErrInvalidListTypeCtr);
             return ((NET_CONN *)0);                            /* Prevent 'break NOT reachable' compiler warning.      */
    }


/*$PAGE*/
    pconn_chain = (NET_CONN *)*pconn_list;                                  /* Start @ conn list head.                  */
    pconn       = (NET_CONN *) 0;
    found       =  DEF_NO;

    while ((pconn_chain != (NET_CONN *)0) &&                                /* Srch ALL net conn chains ..              */
           (found       ==  DEF_NO)) {                                      /* .. until net conn found.                 */

        pconn_chain_next = (NET_CONN *)pconn_chain->NextChainPtr;

        switch (conn_list_type) {
            case NET_CONN_LIST_TYPE_SERVER:
                                                                            /* Cmp conn local addr (see Note #1a1).     */
                 pconn_addr_local = (CPU_INT08U *)&pconn_chain->AddrLocal[0];
                 found_prim_addr  =  Mem_Cmp((void     *)paddr_local,
                                             (void     *)pconn_addr_local,
                                             (CPU_SIZE_T)NET_CONN_CFG_ADDR_LEN);

                 if (found_prim_addr == DEF_YES) {                          /* If local addr found,       ...           */

                     pconn = pconn_chain;

                     while ((pconn != (NET_CONN *)0) &&                     /* ... srch server conn chain ...           */
                            (found ==  DEF_NO)) {                           /* ... until conn found.                    */

                         pconn_next = (NET_CONN *)pconn->NextConnPtr;

                         if (sec_srch_addr_reqd == DEF_YES) {               /* If conn sec addr req'd, ...              */
                                                                            /* ... cmp conn remote addr.                */
                             if (pconn->AddrRemoteValid == DEF_YES) {
                                 pconn_addr_remote = (CPU_INT08U *)&pconn->AddrRemote[0];
                                 found             =  Mem_Cmp((void     *)paddr_remote,
                                                              (void     *)pconn_addr_remote,
                                                              (CPU_SIZE_T)NET_CONN_CFG_ADDR_LEN);
                             }

                         } else if (pconn->AddrRemoteValid == DEF_NO) {     /* Else if conn sec addr NOT avail, ...     */
                             found = DEF_YES;                               /* ... rtn conn.                            */
                         }

                         if (found != DEF_YES) {                            /* If NOT found, adv to next conn.          */
                             pconn  = pconn_next;
                         }
                     }
                 }
                 break;

/*$PAGE*/
            case NET_CONN_LIST_TYPE_CLIENT:
                                                                            /* Cmp conn remote addr (see Note #1a2).    */
                 pconn_addr_remote = (CPU_INT08U *)&pconn_chain->AddrRemote[0];
                 found_prim_addr   =  Mem_Cmp((void     *)paddr_remote,
                                              (void     *)pconn_addr_remote,
                                              (CPU_SIZE_T)NET_CONN_CFG_ADDR_LEN);

                 if (found_prim_addr == DEF_YES) {                          /* If remote addr found,      ...           */

                     pconn = pconn_chain;

                     while ((pconn != (NET_CONN *)0) &&                     /* ... srch client conn chain ...           */
                            (found ==  DEF_NO)) {                           /* ... until conn found.                    */

                         pconn_next = (NET_CONN *)pconn->NextConnPtr;

                         if (pconn->AddrLocalValid  == DEF_YES) {           /* If conn's local addr valid & ...         */
                             if (sec_srch_addr_reqd == DEF_YES) {           /* .. conn sec addr req'd,      ...         */
                                                                            /* .. cmp conn local addr.                  */
                                 pconn_addr_local   = (CPU_INT08U *)&pconn->AddrLocal[0];
                                 found              =  Mem_Cmp((void     *)paddr_local,
                                                               (void     *)pconn_addr_local,
                                                               (CPU_SIZE_T)NET_CONN_CFG_ADDR_LEN);
                             } else {                                       /* Else if conn sec addr NOT req'd, ...     */
                                 found              =  DEF_YES;             /* ... rtn conn.                            */
                             }
                         } else {                                           /* Else conn's local addr NOT valid, ...    */
                             NetConn_Unlink(pconn);                         /* ... unlink conn from conn list    ...    */
                                                                            /* ... (see Notes #3a & #3c).               */
                         }

                         if (found != DEF_YES) {                            /* If NOT found, adv to next conn.          */
                             pconn  = pconn_next;
                         }
                     }
                 }
                 break;


            case NET_CONN_LIST_TYPE_NONE:
            default:                                                        /* See Note #4.                             */
                 NET_CTR_ERR_INC(NetConn_ErrInvalidListTypeCtr);
                 return ((NET_CONN *)0);                                    /* Prevent 'break NOT reachable' warning.   */
        }

        if (found != DEF_YES) {                                             /* If net conn NOT found, ...               */
            pconn_chain = pconn_chain_next;                                 /* ... adv to next net conn chain.          */
        }
    }


    if (found == DEF_YES) {                                                 /* If net conn found, inc conn access ctrs. */
        pconn_chain->ConnChainAccessedCtr++;
        if (pconn_chain->ConnChainAccessedCtr > NetConn_AccessedTh_nbr) {   /* If conn chain accessed > th           .. */
            pconn_chain->ConnChainAccessedCtr = 0;
            if (pconn_chain != *pconn_list) {                               /* .. & conn chain NOT    @ conn list head, */
                                                                            /* .. promote conn chain to conn list head. */
                NetConn_ChainUnlink(pconn_list, pconn_chain);
                NetConn_ChainInsert(pconn_list, pconn_chain);                        
            }
        }

        pconn->ConnAccessedCtr++;
        if (pconn->ConnAccessedCtr > NetConn_AccessedTh_nbr) {              /* If conn accessed > th               ..   */
            pconn->ConnAccessedCtr = 0;
            if (pconn != pconn_chain) {                                     /* .. & conn  NOT   @ conn chain head, ..   */
                                                                            /* .. promote conn to conn chain head.      */
                NetConn_Unlink(pconn);
                NetConn_Add(pconn_list, pconn_chain, pconn, conn_list_type);
            }
        }
    }


    return (pconn);
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                        NetConn_ChainInsert()
*
* Description : (1) Insert a connection chain into a connection list :
*
*                   (a) Insert connection chain at the head of the connection list
*                   (b) Set each chain connection's connection list
*
*
* Argument(s) : pconn_list      Pointer to a connection list.
*               ----------      Argument validated in NetConn_ListSrch().
*
*               pconn_chain     Pointer to a connection chain.
*               -----------     Argument validated in NetConn_ListSrch().
*
* Return(s)   : none.
*
* Caller(s)   : NetConn_ListSrch().
*
* Note(s)     : none.
*********************************************************************************************************
*/

static  void  NetConn_ChainInsert (NET_CONN  **pconn_list,
                                   NET_CONN   *pconn_chain)
{
    NET_CONN  *pconn;
    NET_CONN  *pconn_next;

                                                                /* ------- INSERT CONN CHAIN AT CONN LIST HEAD -------- */
    pconn_chain->PrevChainPtr = (void *)0;
    pconn_chain->NextChainPtr = (void *)(*pconn_list);

    if (*pconn_list != (NET_CONN *)0) {                         /* If conn list NOT empty,                         ...  */
       (*pconn_list)->PrevChainPtr = (void *)pconn_chain;       /* ... insert conn chain before cur conn list head ...  */
    }
   *pconn_list = pconn_chain;                                   /*     Set    conn chain as     new conn list head.     */

                                                                /* ------------ SET CHAIN CONNS' CONN LIST ------------ */
    pconn = pconn_chain;
    while (pconn  != (NET_CONN *)0) {
        pconn->ConnList = (void    **)pconn_list;
        pconn_next      = (NET_CONN *)pconn->NextConnPtr;
        pconn           =  pconn_next;
    }
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                        NetConn_ChainUnlink()
*
* Description : (1) Unlink a connection chain from a connection list :
*
*                   (a) Unlink connection chain
*                   (b) Clear each chain connection's connection list
*
*
* Argument(s) : pconn_list      Pointer to a connection list.
*               ----------      Argument validated in NetConn_ListSrch().
*
*               pconn_chain     Pointer to a connection chain.
*               -----------     Argument validated in NetConn_ListSrch().
*
* Return(s)   : none.
*
* Caller(s)   : NetConn_ListSrch().
*
* Note(s)     : (2) Since NetConn_ChainUnlink() called ONLY to remove & then re-link connection chains,
*                   it is NOT necessary to clear the entry's previous & next chain pointers.  However,
*                   pointers cleared to NULL shown for correctness & completeness.
*********************************************************************************************************
*/

static  void  NetConn_ChainUnlink (NET_CONN  **pconn_list,
                                   NET_CONN   *pconn_chain)
{
    NET_CONN  *pconn_chain_prev;
    NET_CONN  *pconn_chain_next;
    NET_CONN  *pconn;
    NET_CONN  *pconn_next;

                                                                /* --------- UNLINK CONN CHAIN FROM CONN LIST --------- */
    pconn_chain_prev = (NET_CONN *)pconn_chain->PrevChainPtr;
    pconn_chain_next = (NET_CONN *)pconn_chain->NextChainPtr;
                                                                /* Point prev conn chain to next conn chain.            */
    if (pconn_chain_prev != (NET_CONN *)0) {
        pconn_chain_prev->NextChainPtr = (void     *)pconn_chain_next;
    } else {
       *pconn_list                     = (NET_CONN *)pconn_chain_next;
    }
                                                                /* Point next conn chain to prev conn chain.            */
    if (pconn_chain_next != (NET_CONN *)0) {
        pconn_chain_next->PrevChainPtr = (void     *)pconn_chain_prev;
    }

#if (NET_DBG_CFG_MEM_CLR_EN == DEF_ENABLED)                     /* Clr conn chain's chain ptrs (see Note #2).           */
    pconn_chain->PrevChainPtr = (void *)0;
    pconn_chain->NextChainPtr = (void *)0;
#endif

                                                                /* ------------ CLR CHAIN CONNS' CONN LIST ------------ */
    pconn = pconn_chain;
    while (pconn  != (NET_CONN *)0) {
        pconn->ConnList = (void    **)0;
        pconn_next      = (NET_CONN *)pconn->NextConnPtr;
        pconn           =  pconn_next;
    }
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                            NetConn_Add()
*
* Description : (1) Add a network connection into a network connection list :
*
*                   (a) New network connection chains are added at the head of a network connection list.
*
*                   (b) New network connections are added at or immediately following the head of a network 
*                       connection chain :
*
*                       (1) New network connections in a server connection list are added ...
*
*                           (A) As the second connection immediately following the connection chain head,
*                               if the connection chain head connection is an unconnected server connection
*                               (i.e. no remote connection address is available).
*
*                           (B) At the head of a connection chain, if the current connection chain head is 
*                               NOT an unconnected server connection.
*
*                       (2) New network connections in a client connection list are added at the head of a 
*                           network connection chain.
*
*
* Argument(s) : pconn_list          Pointer to a network connection list.
*               ----------          Argument validated in NetConn_ListAdd(),
*                                                         NetConn_ListSrch().
*
*               pconn_chain         Pointer to a network connection chain.
*
*               pconn               Pointer to a network connection.
*               -----               Argument validated in NetConn_ListAdd(),
*                                                         NetConn_ListSrch().
*
*               conn_list_type      Network connection list type :
*
*                                       NET_CONN_LIST_TYPE_SERVER       Connection list organized primarily
*                                                                           by local  address.
*                                       NET_CONN_LIST_TYPE_CLIENT       Connection list organized primarily
*                                                                           by remote address.
*
* Return(s)   : none.
*
* Caller(s)   : NetConn_ListAdd(),
*               NetConn_ListSrch().
*
* Note(s)     : none.  
*********************************************************************************************************
*/
/*$PAGE*/
static  void  NetConn_Add (NET_CONN            **pconn_list,
                           NET_CONN             *pconn_chain,
                           NET_CONN             *pconn,
                           NET_CONN_LIST_TYPE    conn_list_type)
{
    CPU_BOOLEAN   insert_conn_list_head;
    NET_CONN     *pconn_next;
    NET_CONN     *pconn_chain_prev;
    NET_CONN     *pconn_chain_next;


    if (pconn_chain == (NET_CONN *)0) {                         /* If conn chain empty, ...                             */
                                                                /* ... insert net conn as new conn chain (see Note #1a).*/
        pconn->PrevChainPtr = (void *)0;
        pconn->NextChainPtr = (void *)(*pconn_list);
        pconn->PrevConnPtr  = (void *)0;
        pconn->NextConnPtr  = (void *)0;

        if (*pconn_list != (NET_CONN *)0) {                     /* If conn list NOT empty,                   ...        */
           (*pconn_list)->PrevChainPtr = (void *)pconn;         /* ... insert conn before cur conn list head ...        */
        }
       *pconn_list = pconn;                                     /*     Set    conn as     new conn list head.           */

    } else {                                                    /* Else add net conn into existing conn chain.          */

        insert_conn_list_head = ((conn_list_type               == NET_CONN_LIST_TYPE_SERVER) &&
                                 (pconn_chain->AddrRemoteValid != DEF_YES)) ? DEF_NO : DEF_YES;

        if (insert_conn_list_head != DEF_NO) {                  /* If conn chain head NOT an unconnected server conn,   */
                                                                /* ... add net conn as new conn chain head          ... */
                                                                /* ... (see Notes #1b1B & #1b2).                        */
            pconn_chain_prev          = (NET_CONN *)pconn_chain->PrevChainPtr;
            pconn_chain_next          = (NET_CONN *)pconn_chain->NextChainPtr;
            pconn_chain->PrevChainPtr = (void     *)0;
            pconn_chain->NextChainPtr = (void     *)0;
            pconn_chain->PrevConnPtr  = (void     *)pconn;

            pconn->PrevConnPtr        = (void     *)0;
            pconn->NextConnPtr        = (void     *)pconn_chain;

            pconn->PrevChainPtr       = (void     *)pconn_chain_prev;
            if (pconn_chain_prev != (NET_CONN *)0) {
                pconn_chain_prev->NextChainPtr = (void     *)pconn;
            } else {
               *pconn_list                     = (NET_CONN *)pconn;
            }

            pconn->NextChainPtr   = (void     *)pconn_chain_next;
            if (pconn_chain_next != (NET_CONN *)0) {
                pconn_chain_next->PrevChainPtr = (void     *)pconn;
            }
                                                                /* Inherit conn chain accessed ctr.                     */
            pconn->ConnChainAccessedCtr       = pconn_chain->ConnChainAccessedCtr;
            pconn_chain->ConnChainAccessedCtr = 0;

        } else {                                                /* Else add net conn after conn chain head ...          */
                                                                /* ... (see Note #1b1A).                                */
            pconn->PrevChainPtr      = (void     *)0;
            pconn->NextChainPtr      = (void     *)0;

            pconn->PrevConnPtr       = (void     *)pconn_chain;

            pconn_next               = (NET_CONN *)pconn_chain->NextConnPtr;
            pconn->NextConnPtr       = (void     *)pconn_next;
            pconn_chain->NextConnPtr = (void     *)pconn;
            if (pconn_next != (NET_CONN *)0) {
                pconn_next->PrevConnPtr = (void *)pconn;
            }
        }
    }

    pconn->ConnList     = (void **)pconn_list;                  /* Mark conn's conn list ownership.                     */
    pconn->ConnListType =  conn_list_type;
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                          NetConn_Unlink()
*
* Description : Unlink a network connection from its network connection list.
*
* Argument(s) : pconn       Pointer to a network connection.
*               -----       Argument validated in NetConn_ListUnlink(),
*                                                 NetConn_ListSrch(),
*                                                 NetConn_FreeHandler().
*
* Return(s)   : none.
*
* Caller(s)   : NetConn_ListUnlink(),
*               NetConn_ListSrch(),
*               NetConn_FreeHandler().
*
* Note(s)     : (1) Since NetConn_Unlink() called ONLY to remove & then re-link or free network
*                   connections, it is NOT necessary to clear the entry's previous & next chain/
*                   connection pointers.  However, pointers cleared to NULL shown for correctness
*                   & completeness.
*********************************************************************************************************
*/
/*$PAGE*/
static  void  NetConn_Unlink (NET_CONN  *pconn)
{
    NET_CONN  **pconn_list;
    NET_CONN   *pconn_prev;
    NET_CONN   *pconn_next;
    NET_CONN   *pconn_chain_prev;
    NET_CONN   *pconn_chain_next;


    pconn_list = (NET_CONN **)pconn->ConnList;
    if (pconn_list == (NET_CONN **)0) {                                 /* If net conn NOT in conn list, ...            */
        return;                                                         /* ... exit unlink.                             */
    }

                                                                        /* ----- UNLINK NET CONN FROM CONN CHAIN ------ */
    pconn_prev = (NET_CONN *)pconn->PrevConnPtr;
    pconn_next = (NET_CONN *)pconn->NextConnPtr;
                                                                
    if (pconn_prev != (NET_CONN *)0) {                                  /* If prev net conn non-NULL, ...               */
                                                                        /* ... unlink conn from middle of conn chain.   */
        pconn_prev->NextConnPtr = (void *)pconn_next;                   /* Point prev conn to next conn.                */

        if (pconn_next != (NET_CONN *)0) {                              /* If next net conn non-NULL, ...               */
            pconn_next->PrevConnPtr = (void *)pconn_prev;               /* ... point next conn to prev conn.            */
        }

    } else {                                                            /* Else unlink conn chain head.                 */
        pconn_chain_prev = (NET_CONN *)pconn->PrevChainPtr;
        pconn_chain_next = (NET_CONN *)pconn->NextChainPtr;

        if (pconn_next  != (NET_CONN *)0) {                             /* If next conn in conn chain non-NULL, ...     */
                                                                        /* ... promote next conn to conn chain head.    */
            pconn_next->PrevChainPtr = (void  *)pconn_chain_prev;
            if (pconn_chain_prev != (NET_CONN *)0) {
                pconn_chain_prev->NextChainPtr = (void     *)pconn_next;
            } else {
               *pconn_list                     = (NET_CONN *)pconn_next;
            }

            pconn_next->NextChainPtr = (void  *)pconn_chain_next;
            if (pconn_chain_next != (NET_CONN *)0) {
                pconn_chain_next->PrevChainPtr = (void     *)pconn_next;
            }

            pconn_next->PrevConnPtr          = (void *)0;
                                                                        /* Inherit conn chain accessed ctr.             */
            pconn_next->ConnChainAccessedCtr =  pconn->ConnChainAccessedCtr;
            pconn->ConnChainAccessedCtr      =  0;

        } else {                                                        /* Else remove conn list entirely.              */
            if (pconn_chain_prev != (NET_CONN *)0) {
                pconn_chain_prev->NextChainPtr = (void     *)pconn_chain_next;
            } else {
               *pconn_list                     = (NET_CONN *)pconn_chain_next;
            }

            if (pconn_chain_next != (NET_CONN *)0) {
                pconn_chain_next->PrevChainPtr = (void     *)pconn_chain_prev;
            }
        }
    }

    pconn->ConnList     = (void **)0;                                   /* Clr net conn's conn list ownership.          */
    pconn->ConnListType =  NET_CONN_LIST_TYPE_NONE;

#if (NET_DBG_CFG_MEM_CLR_EN == DEF_ENABLED)                             /* Clr net conn's chain/conn ptrs (see Note #1).*/
    pconn->PrevChainPtr = (void  *)0;
    pconn->NextChainPtr = (void  *)0;
    pconn->PrevConnPtr  = (void  *)0;
    pconn->NextConnPtr  = (void  *)0;
#endif
}


/*$PAGE*/
/*
*********************************************************************************************************
*                                             MODULE END
*
* Note(s) : (1) See 'MODULE  Note #1' & 'net_conn.h  MODULE  Note #1'.
*********************************************************************************************************
*/

#endif                                                          /* End of net conn module include (see Note #1).        */

