ANSC_STATUS
AnscDktoTsaRecvAppMessage
    (
        ANSC_HANDLE                 hThisObject,
        ANSC_HANDLE                 hMessageBdo
    )
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PANSC_DAEMON_SOCKET_TCP_OBJECT  pMyObject    = (PANSC_DAEMON_SOCKET_TCP_OBJECT)hThisObject;
    PANSC_DAEMON_SERVER_TCP_OBJECT  pServer      = (PANSC_DAEMON_SERVER_TCP_OBJECT)pMyObject->hDaemonServer;
    PANSC_DAEMON_ENGINE_TCP_OBJECT  pEngine      = (PANSC_DAEMON_ENGINE_TCP_OBJECT)pMyObject->hDaemonEngine;
    PANSC_DSTO_WORKER_OBJECT        pWorker      = (PANSC_DSTO_WORKER_OBJECT      )pServer->hWorker;
    PANSC_BUFFER_DESCRIPTOR         pPayloadBdo  = (PANSC_BUFFER_DESCRIPTOR       )hMessageBdo;
    void*                           pRecvBuffer  = (void*                         )NULL;
    ANSC_HANDLE                     hRecvHandle  = (ANSC_HANDLE                   )NULL;
    ULONG                           ulRecvSize   = (ULONG                         )0;
    ULONG                           ulLeftSize   = (ULONG                         )AnscBdoGetBlockSize(pPayloadBdo);
    ULONG                           ulCopySize   = (ULONG                         )0;
    ULONG                           ulServingT1  = 0;
    ULONG                           ulServingT2  = 0;
    ULONG                           ulWaitCount  = 0;

    /*
     * Since the TLS handshake is done in the asynchronous task instead of the socket_recv task,
     * it's possible that we start receiving TLS client data traffic (i.e. HTTP) before handshake
     * task considers the handshaking is done. To accommodate such race condition, we need to sleep
     * for a while if there's no buffer available.
     */
    while ( !pMyObject->GetRecvBuffer
                (
                    (ANSC_HANDLE)pMyObject,
                    &ulRecvSize
                ) )
    {
        AnscSleep(10);

        ulWaitCount++;

        if ( ulWaitCount > 30 ) /* sleep for 300ms */
        {
            returnStatus = ANSC_STATUS_INTERNAL_ERROR;

            goto  EXIT1;
        }
    }

    while ( ulLeftSize > 0 )
    {
        pRecvBuffer =
            pMyObject->GetRecvBuffer
                (
                    (ANSC_HANDLE)pMyObject,
                    &ulRecvSize
                );

        if ( !pRecvBuffer )
        {
            returnStatus =
                pWorker->Notify
                    (
                        pWorker->hWorkerContext,
                        (ANSC_HANDLE)pMyObject,
                        ANSC_DSTOWO_EVENT_RESOURCES,
                        (ANSC_HANDLE)NULL
                    );

            break;
        }
        else if ( ulRecvSize == 0 )
        {
            pMyObject->ToClean((ANSC_HANDLE)pMyObject, TRUE, 2);

            break;
        }

        if ( ulRecvSize >= ulLeftSize )
        {
            ulCopySize = ulLeftSize;
        }
        else
        {
            ulCopySize = ulRecvSize;
        }

        if ( TRUE )
        {
            AnscCopyMemory
                (
                    pRecvBuffer,
                    AnscBdoGetBlock(pPayloadBdo),
                    ulCopySize
                );

            AnscBdoShrinkRight(pPayloadBdo, ulCopySize);

            ulLeftSize -= ulCopySize;
        }

        pMyObject->RecvBytesCount += ulCopySize;
        pMyObject->LastRecvAt      = AnscGetTickInSecondsAbs();

        /*
         * We have successfully transferred the received data into the buffer supplied by the
         * socket owener though may not use up the while buffer. Now is time to notify our loyal
         * socket owner about this exciting event.
         */
        ulServingT1  = AnscGetTickInMilliSeconds();
        returnStatus =
            pMyObject->Recv
                (
                    (ANSC_HANDLE)pMyObject,
                    pRecvBuffer,
                    ulCopySize
                );
        ulServingT2  = AnscGetTickInMilliSeconds();

        pEngine->AvgServingTime =
            (pEngine->AvgServingTime == 0)? (ulServingT2 - ulServingT1) : ((ulServingT2 - ulServingT1) + pEngine->AvgServingTime * 7) / 8;
        pEngine->TscCount++;
    }

    goto  EXIT1;


    /******************************************************************
                GRACEFUL ROLLBACK PROCEDURES AND EXIT DOORS
    ******************************************************************/

EXIT1:

    if ( pPayloadBdo )
    {
        AnscFreeBdo((ANSC_HANDLE)pPayloadBdo);
    }

    return  returnStatus;
}
ANSC_STATUS
BbhmDiagipRecv
    (
        ANSC_HANDLE                 hThisObject,
        ANSC_HANDLE                 hSinkObject,
        PVOID                       buffer,
        ULONG                       ulSize
    )
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PBBHM_DIAG_IP_PING_OBJECT       pMyObject    = (PBBHM_DIAG_IP_PING_OBJECT)hThisObject;
    PBBHM_IP_PING_PROPERTY          pProperty    = (PBBHM_IP_PING_PROPERTY        )&pMyObject->Property;
    PBBHM_IP_PING_TDO_OBJECT        pStateTimer  = (PBBHM_IP_PING_TDO_OBJECT      )pMyObject->hStateTimer;
    PBBHM_IP_PING_SINK_OBJECT       pSink        = (PBBHM_IP_PING_SINK_OBJECT     )hSinkObject;
    PANSC_XSOCKET_OBJECT            pSocket      = (PANSC_XSOCKET_OBJECT          )pSink->GetXsocket((ANSC_HANDLE)pSink);
    PIPV4_HEADER                    pIpv4Header  = (PIPV4_HEADER                  )NULL;
    /*PIPV6_HEADER                    pIpv6Header  = (PIPV6_HEADER                  )NULL;*/
    PICMPV4_ECHO_MESSAGE            pIcmpHeader  = (PICMPV4_ECHO_MESSAGE          )NULL;
    PBBHM_IP_PING_ECHO_ENTRY        pMEchoEntry  = NULL;
    ULONG                           StopTime     = 0;

    StopTime = AnscGetTickInMilliSeconds();

    if ( pProperty->Status != BBHM_IP_PING_STATUS_RUNNING )
    {
        return  ANSC_STATUS_UNAPPLICABLE;
    }

    if ( pMyObject->IPProtocol == XSKT_SOCKET_AF_INET )
    {
        pIpv4Header = (PIPV4_HEADER)buffer;
        pIcmpHeader = (PICMPV4_ECHO_MESSAGE)AnscIpv4GetPayload(pIpv4Header);

        if ( ! AnscEqualString(pSocket->PeerName, pProperty->pDstAddrName, TRUE)/*(pSocket->PeerAddress.Value != pProperty->DstIp.Value)*/
            || (AnscIcmpv4EchoGetId(pIcmpHeader) !=  tempId) )
        {
            return  ANSC_STATUS_FAILURE;
        }

        if ( (AnscIcmpv4EchoGetType(pIcmpHeader) == ICMP_TYPE_DESTINATION_UNREACHABLE)
            || (AnscIcmpv4EchoGetType(pIcmpHeader) == ICMP_TYPE_TIME_EXCEEDED)
            || (AnscIcmpv4EchoGetType(pIcmpHeader) == ICMP_TYPE_PARAMETER_PROBLEM)
            || (AnscIcmpv4EchoGetType(pIcmpHeader) == ICMP_TYPE_SOURCE_QUENCH)
            || (AnscIcmpv4EchoGetType(pIcmpHeader) == ICMP_TYPE_REDIRECT))
        {
            pProperty->NumIcmpError ++;
            pProperty->IcmpError = AnscIcmpv4EchoGetType(pIcmpHeader);

            pMEchoEntry = (PBBHM_IP_PING_ECHO_ENTRY)AnscAllocateMemory(sizeof(BBHM_IP_PING_ECHO_ENTRY));
            if ( pMEchoEntry )
            {
                pMEchoEntry->ICMPType = AnscIcmpv4EchoGetType(pIcmpHeader);
                AnscAcquireLock(&pMyObject->MiddleResultLock);
                AnscSListPushEntryAtBack(&pMyObject->MiddleResult, &pMEchoEntry->Linkage);
                AnscReleaseLock(&pMyObject->MiddleResultLock);
            }

            return  ANSC_STATUS_FAILURE;
        }

        returnStatus =
            pMyObject->SetStopTime
                (
                    (ANSC_HANDLE)pMyObject,
                    AnscIcmpv4EchoGetSeqNumber(pIcmpHeader),
                    AnscIpv4GetTotalLength(pIpv4Header) - sizeof(IPV4_HEADER) - sizeof(ICMPV4_HEADER),
                    AnscIpv4GetTtl(pIpv4Header),
                    StopTime
                );
    }
    else if ( pMyObject->IPProtocol == XSKT_SOCKET_AF_INET6 )
    {
        pIcmpHeader = (PICMPV6_ECHO_MESSAGE)buffer;

        if ( ! AnscEqualString(pSocket->PeerName, pProperty->pDstAddrName, TRUE)/*(pSocket->PeerAddress.Value != pProperty->DstIp.Value)*/
            || (AnscIcmpv6EchoGetId(pIcmpHeader) !=  tempId) )
        {
            return  ANSC_STATUS_FAILURE;
        }

        if ( (AnscIcmpv6EchoGetType(pIcmpHeader) == ICMP6_TYPE_DESTINATION_UNREACHABLE)
            || (AnscIcmpv6EchoGetType(pIcmpHeader) == ICMP6_TYPE_TIME_EXCEEDED)
            || (AnscIcmpv6EchoGetType(pIcmpHeader) == ICMP6_TYPE_PARAMETER_PROBLEM)
            || (AnscIcmpv6EchoGetType(pIcmpHeader) == ICMP6_TYPE_PACKET_TOO_BIG))
        {
            pProperty->NumIcmpError ++;
            pProperty->IcmpError = AnscIcmpv6EchoGetType(pIcmpHeader);

            pMEchoEntry = (PBBHM_IP_PING_ECHO_ENTRY)AnscAllocateMemory(sizeof(BBHM_IP_PING_ECHO_ENTRY));
            if ( pMEchoEntry )
            {
                pMEchoEntry->ICMPType = AnscIcmpv6EchoGetType(pIcmpHeader);
                AnscAcquireLock(&pMyObject->MiddleResultLock);
                AnscSListPushEntryAtBack(&pMyObject->MiddleResult, &pMEchoEntry->Linkage);
                AnscReleaseLock(&pMyObject->MiddleResultLock);
            }

            return  ANSC_STATUS_FAILURE;
        }

        returnStatus =
            pMyObject->SetStopTime
                (
                    (ANSC_HANDLE)pMyObject,
                    AnscIcmpv6EchoGetSeqNumber(pIcmpHeader),
                    ulSize,
                    0,           /* Hop Limit */
                    StopTime
                );
    }

    if ( returnStatus == ANSC_STATUS_SUCCESS )
    {
        pProperty->PktsRecv ++;
    }

    if ( pProperty->PktsRecv == pProperty->NumPkts )
    {
        pMyObject->SetStatus((ANSC_HANDLE)pMyObject, BBHM_IP_PING_STATUS_COMPLETE);
        pMyObject->Stop((ANSC_HANDLE)pMyObject);
    }

    return  returnStatus;
}
ANSC_STATUS
BbhmDiagipStart
    (
        ANSC_HANDLE                 hThisObject
    )
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PBBHM_DIAG_IP_PING_OBJECT       pMyObject    = (PBBHM_DIAG_IP_PING_OBJECT)hThisObject;
    PDSLH_PING_INFO                 pDiagInfo    = (PDSLH_PING_INFO)pMyObject->hDslhDiagInfo;
    PBBHM_IP_PING_PROPERTY          pProperty    = (PBBHM_IP_PING_PROPERTY  )&pMyObject->Property;
    PBBHM_IP_PING_TDO_OBJECT        pStateTimer  = (PBBHM_IP_PING_TDO_OBJECT)pMyObject->hStateTimer;
    PBBHM_IP_PING_SINK_OBJECT       pSink        = (PBBHM_IP_PING_SINK_OBJECT)pMyObject->hSinkObject;
    PANSC_XSOCKET_OBJECT            pSocket      = (PANSC_XSOCKET_OBJECT     )pSink->GetXsocket((ANSC_HANDLE)pSink);
    ULONG                           numPkts      = pProperty->NumPkts;
    ULONG                           pktSize      = pProperty->PktSize;
    PCHAR                           pSendBuffer  = pMyObject->hSendBuffer;
    ULONG                           i            = 0;
    PICMPV4_ECHO_MESSAGE            pIcmpHeader  = NULL;
    ULONG                           StartTime    = 0;
    UCHAR                           SrcIp[4]     = {0, 0, 0, 0};

    if ( !pMyObject->bActive )
    {
        pProperty->Status = BBHM_IP_PING_STATUS_ABORT;

        pMyObject->Stop(hThisObject);

        return  ANSC_STATUS_FAILURE;
    }

    pMyObject->ResetPropertyCounter((ANSC_HANDLE)pMyObject);

    pSocket->SetPeerName     ((ANSC_HANDLE)pSocket, pProperty->pDstAddrName);
    pSocket->SetHostName     ((ANSC_HANDLE)pSocket, pProperty->pSrcAddrName);
    /*
    pSocket->SetHostAddress  ((ANSC_HANDLE)pSocket, SrcIp                 );
    pSocket->SetHostPort     ((ANSC_HANDLE)pSocket, 0                     );
    */

    /*pSocket->SetTransportType((ANSC_HANDLE)pSocket, ICMP_TRANSPORT        );*/
    pSocket->SetType         ((ANSC_HANDLE)pSocket, ANSC_XSOCKET_TYPE_RAW );
    pSocket->SetMode         ((ANSC_HANDLE)pSocket, 0                     );

    pSocket->SetXsink        ((ANSC_HANDLE)pSocket, (ANSC_HANDLE)pSink    );

    /*
     * The underlying socket wrapper may require an explicit startup() call, such is the case on
     * Microsoft windows platforms. The wrapper initialization has to done for each task. On most
     * real-time operating systems, this call is not required.
     */
    AnscStartupXsocketWrapper((ANSC_HANDLE)pMyObject);

    /* For IPv4/IPv6 compatible purpose we shall resolve the address first */
	returnStatus = BbhmDiagResolvAddr(hThisObject);

    if ( returnStatus != ANSC_STATUS_SUCCESS )
    {
        pProperty->Status = BBHM_IP_PING_STATUS_ERROR_HostName;

        pMyObject->Stop(hThisObject);

        return ANSC_STATUS_FAILURE;
    }

    pMyObject->IPProtocol = pSocket->GetIpProtocol((ANSC_HANDLE)pSocket);

    if ( pMyObject->IPProtocol == XSKT_SOCKET_AF_INET )
    {
        pSocket->SetTransportType((ANSC_HANDLE)pSocket, IP4_PROTOCOL_ICMP);
    }
    else if ( pMyObject->IPProtocol == XSKT_SOCKET_AF_INET6 )
    {
        pSocket->SetTransportType((ANSC_HANDLE)pSocket, IP6_PROTOCOL_ICMP);
    }
    else
    {
        pProperty->Status = BBHM_IP_PING_STATUS_ABORT;

        pMyObject->Stop(hThisObject);

        return  ANSC_STATUS_FAILURE;
    }

    /*
     * We shall open the socket and listen on it right away. Since we're still in the context of
     * initialiation, the wrapper module must be aware of the fact that the socket is opened before
     * the first call returns.
     */
    returnStatus = pSocket->Bind((ANSC_HANDLE)pSocket);

    if ( returnStatus != ANSC_STATUS_SUCCESS )
    {
        pProperty->Status = BBHM_IP_PING_STATUS_ABORT;

        pMyObject->Stop(hThisObject);

        return  ANSC_STATUS_FAILURE;
    }

    returnStatus = pSocket->Open((ANSC_HANDLE)pSocket); /* Create recv task */

    if ( returnStatus != ANSC_STATUS_SUCCESS )
    {
        AnscTrace("Socket Open Failed!\n");
        pProperty->Status = BBHM_IP_PING_STATUS_ABORT;

        pMyObject->Stop(hThisObject);

        return  ANSC_STATUS_FAILURE;
    }

    if ( !pSendBuffer )
    {
        returnStatus = ANSC_STATUS_FAILURE;
        pProperty->Status = BBHM_IP_PING_STATUS_ABORT;

        pMyObject->Stop(hThisObject);

        return  ANSC_STATUS_FAILURE;
    }

    /* Set DSCP */
    if ( pDiagInfo->DSCP != 0 )
    {
        pSocket->ApplyDSCP((ANSC_HANDLE)pSocket, pDiagInfo->DSCP);
    }

    AnscSleep(100);

    if ( pMyObject->IPProtocol == XSKT_SOCKET_AF_INET )
    {
        pIcmpHeader = (PICMPV4_ECHO_MESSAGE)pMyObject->hSendBuffer;

        AnscIcmpv4EchoSetType        (pIcmpHeader, ICMP_TYPE_ECHO_REQUEST   );
        AnscIcmpv4EchoSetCode        (pIcmpHeader, 0                        );
        AnscIcmpv4EchoSetId          (pIcmpHeader, tempId                   );
        AnscIcmpv4EchoSetSeqNumber   (pIcmpHeader, (USHORT)pMyObject->GetPktsSent((ANSC_HANDLE)pMyObject));

        for ( i = 0; i < pktSize; i++ )
        {
            ((PUCHAR)pMyObject->hSendBuffer)[i + sizeof(ICMPV4_HEADER)] = (UCHAR)i;
        }

        AnscIcmpv4EchoSetChecksum   (pIcmpHeader, 0                                 );
        AnscIcmpv4CalculateChecksum (((PICMPV4_HEADER)pIcmpHeader), pktSize + sizeof(ICMPV4_HEADER));
    }
    else if ( pMyObject->IPProtocol == XSKT_SOCKET_AF_INET6 )
    {
        pIcmpHeader = (PICMPV6_ECHO_MESSAGE)pMyObject->hSendBuffer;

        AnscIcmpv6EchoSetType        (pIcmpHeader, ICMP6_TYPE_ECHO_REQUEST  );
        AnscIcmpv6EchoSetCode        (pIcmpHeader, 0                        );
        AnscIcmpv6EchoSetId          (pIcmpHeader, tempId                   );
        AnscIcmpv6EchoSetSeqNumber   (pIcmpHeader, (USHORT)pMyObject->GetPktsSent((ANSC_HANDLE)pMyObject));

        for ( i = 0; i < pktSize; i++ )
        {
            ((PUCHAR)pMyObject->hSendBuffer)[i + sizeof(ICMPV6_HEADER)] = (UCHAR)i;
        }
    }

    pStateTimer->SetTimerType((ANSC_HANDLE)pStateTimer, ANSC_TIMER_TYPE_SPORADIC);
    pStateTimer->SetInterval ((ANSC_HANDLE)pStateTimer, pProperty->TimeBetween  );
    pStateTimer->SetCounter  ((ANSC_HANDLE)pStateTimer, pProperty->NumPkts      );
/*
    pSocket->SetPeerAddress  ((ANSC_HANDLE)pSocket    , pProperty->DstIp.Dot    );
    pSocket->SetPeerPort     ((ANSC_HANDLE)pSocket    , 0                       );
*/
    pMyObject->SetStatus((ANSC_HANDLE)pMyObject, BBHM_IP_PING_STATUS_RUNNING);

    pStateTimer->Start       ((ANSC_HANDLE)pStateTimer);

    StartTime = AnscGetTickInMilliSeconds();

    if ( pMyObject->IPProtocol == XSKT_SOCKET_AF_INET )
    {
        returnStatus =
            pMyObject->AddEchoEntry
                (
                    (ANSC_HANDLE)pMyObject,
                    AnscIcmpv4EchoGetSeqNumber(pIcmpHeader),
                    StartTime
                );

        returnStatus =
            pMyObject->Send
                (
                    (ANSC_HANDLE)pMyObject,
                    (ANSC_HANDLE)pMyObject->hSinkObject,
                    (PVOID)pMyObject->hSendBuffer,
                    pktSize + sizeof(ICMPV4_HEADER)
                );
    }
    else if ( pMyObject->IPProtocol == XSKT_SOCKET_AF_INET6 )
    {
        returnStatus =
            pMyObject->AddEchoEntry
                (
                    (ANSC_HANDLE)pMyObject,
                    AnscIcmpv6EchoGetSeqNumber(pIcmpHeader),
                    StartTime
                );

        returnStatus =
            pMyObject->Send
                (
                    (ANSC_HANDLE)pMyObject,
                    (ANSC_HANDLE)pMyObject->hSinkObject,
                    (PVOID)pMyObject->hSendBuffer,
                    pktSize + sizeof(ICMPV6_HEADER)
                );
    }

    pProperty->PktsSent++;

    return  returnStatus;

}
ANSC_STATUS
BbhmDiagipExpire1
    (
        ANSC_HANDLE                 hThisObject
    )
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PBBHM_DIAG_IP_PING_OBJECT       pMyObject    = (PBBHM_DIAG_IP_PING_OBJECT       )hThisObject;
    PBBHM_IP_PING_PROPERTY          pProperty    = (PBBHM_IP_PING_PROPERTY          )&pMyObject->Property;
    PBBHM_IP_PING_TDO_OBJECT        pStateTimer  = (PBBHM_IP_PING_TDO_OBJECT        )pMyObject->hStateTimer;
    PBBHM_IP_PING_SINK_OBJECT       pSink        = (PBBHM_IP_PING_SINK_OBJECT       )pMyObject->hSinkObject;
    ULONG                           pktSize      = pProperty->PktSize;
    PICMPV4_ECHO_MESSAGE            pIcmpHeader  = NULL;
    /*USHORT                          oldSeqNumber = AnscIcmpv4EchoGetSeqNumber(pIcmpHeader);*/
    ULONG                           StartTime    = 0;
    /*
    AnscIcmpv4EchoSetSeqNumber(pIcmpHeader, AnscReadUshort(&pProperty->PktsSent));
    AnscIcmpv4UpdateChecksumUshort(pIcmpHeader, oldSeqNumber, AnscReadUshort(&pProperty->PktsSent));
*/
    if ( pMyObject->IPProtocol == XSKT_SOCKET_AF_INET )
    {
        pIcmpHeader  = (PICMPV4_ECHO_MESSAGE)pMyObject->hSendBuffer;

        AnscIcmpv4EchoSetSeqNumber  (pIcmpHeader, (USHORT)pMyObject->GetPktsSent((ANSC_HANDLE)pMyObject));

        AnscIcmpv4EchoSetChecksum   (pIcmpHeader, 0                                                     );
        AnscIcmpv4CalculateChecksum (((PICMPV4_HEADER)pIcmpHeader), pktSize + sizeof(ICMPV4_HEADER)     );

        StartTime = AnscGetTickInMilliSeconds();

        returnStatus =
            pMyObject->AddEchoEntry
                (
                    (ANSC_HANDLE)pMyObject,
                    AnscIcmpv4EchoGetSeqNumber(pIcmpHeader),
                    StartTime
                );

        returnStatus =
            pMyObject->Send
                (
                    (ANSC_HANDLE)pMyObject,
                    (ANSC_HANDLE)pMyObject->hSinkObject,
                    (PVOID)pMyObject->hSendBuffer,
                    pktSize + sizeof(ICMPV4_HEADER)
                );
    }
    else if ( pMyObject->IPProtocol == XSKT_SOCKET_AF_INET6 )
    {
        pIcmpHeader  = (PICMPV6_ECHO_MESSAGE)pMyObject->hSendBuffer;

        AnscIcmpv6EchoSetSeqNumber  (pIcmpHeader, (USHORT)pMyObject->GetPktsSent((ANSC_HANDLE)pMyObject));

        AnscIcmpv6EchoSetChecksum   (pIcmpHeader, 0                                                     );

        StartTime = AnscGetTickInMilliSeconds();

        returnStatus =
            pMyObject->AddEchoEntry
                (
                    (ANSC_HANDLE)pMyObject,
                    AnscIcmpv6EchoGetSeqNumber(pIcmpHeader),
                    StartTime
                );

        returnStatus =
            pMyObject->Send
                (
                    (ANSC_HANDLE)pMyObject,
                    (ANSC_HANDLE)pMyObject->hSinkObject,
                    (PVOID)pMyObject->hSendBuffer,
                    pktSize + sizeof(ICMPV6_HEADER)
                );
    }
    else
    {
        CcspTraceError(("IPProtocol error !!\n"));
    }

    pProperty->PktsSent++;

    return  returnStatus;
}
ANSC_STATUS
BbhmDiagipStop
    (
        ANSC_HANDLE                 hThisObject
    )
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PBBHM_DIAG_IP_PING_OBJECT       pMyObject    = (PBBHM_DIAG_IP_PING_OBJECT     )hThisObject;
    PBBHM_IP_PING_PROPERTY          pProperty    = (PBBHM_IP_PING_PROPERTY        )&pMyObject->Property;
    PBBHM_IP_PING_TDO_OBJECT        pStateTimer  = (PBBHM_IP_PING_TDO_OBJECT      )pMyObject->hStateTimer;
    PBBHM_IP_PING_SINK_OBJECT       pSink        = (PBBHM_IP_PING_SINK_OBJECT     )pMyObject->hSinkObject;
    PANSC_XSOCKET_OBJECT            pSocket      = NULL;
    PDSLH_PING_INFO                 pDslhDiagInfo= (PDSLH_PING_INFO               )pMyObject->hDslhDiagInfo;
    PSINGLE_LINK_ENTRY              pSLinkEntry  = NULL;
    PBBHM_IP_PING_ECHO_ENTRY        pMEchoEntry  = NULL;
    SLIST_HEADER                    MiddleResult;
    ULONG                           i            = 0;
    ULONG                           MaxRetrieve  = 10;
    ULONG                           nRead        = 0;

    if ( pMyObject->bActive )
    {
        ULONG                       ulMin = 0;
        ULONG                       ulMax = 0;
        ULONG                       ulSum = 0;
        ULONG                       ulTime;

        pStateTimer->Stop((ANSC_HANDLE)pStateTimer);
        pStateTimer->SetStopTime((ANSC_HANDLE)pStateTimer, AnscGetTickInMilliSeconds());

        returnStatus =
            pMyObject->CalculateResult
                (
                    (ANSC_HANDLE)pMyObject
                );

        for (i = 0; i < MaxRetrieve; i++)
        {
            AnscAcquireLock(&pMyObject->MiddleResultLock);
            MiddleResult = pMyObject->MiddleResult;
            AnscReleaseLock(&pMyObject->MiddleResultLock);
            if (MiddleResult.Depth == 0)
            {
                break;
            }
            AnscSleep(100);
        }

        AnscAcquireLock(&pMyObject->MiddleResultLock);

        nRead = pMyObject->MiddleResult.Depth;
        pSLinkEntry = AnscSListPopEntry(&pMyObject->MiddleResult);
        while ( pSLinkEntry )
        {
            pMEchoEntry = (PBBHM_IP_PING_ECHO_ENTRY)ACCESS_BBHM_IP_PING_ECHO_ENTRY(pSLinkEntry);
            pSLinkEntry = AnscSListPopEntry(&pMyObject->MiddleResult);

            ulTime = pMEchoEntry->StopTime - pMEchoEntry->StartTime;

            /* calculate min, max, sum */
            if ( ulSum == 0 )
            {
                ulMin = ulMax = ulSum = ulTime;
            }
            else
            {
                if ( ulMin > ulTime )
                {
                    ulMin = ulTime;
                }

                if ( ulMax < ulTime )
                {
                    ulMax = ulTime;
                }

                ulSum += ulTime;
            }

            AnscFreeMemory(pMEchoEntry);
        }

        AnscReleaseLock(&pMyObject->MiddleResultLock);

        if ( nRead != 0 )
        {
            pProperty->AvgRTT   = ulSum/nRead;
            pProperty->MinRTT   = ulMin;
            pProperty->MaxRTT   = ulMax;
        }

        if ( pSink )
        {
            pSocket = (PANSC_XSOCKET_OBJECT             )pSink->GetXsocket((ANSC_HANDLE)pSink);
            pSocket->Close((ANSC_HANDLE)pSocket);
        }
    }

    switch ( pMyObject->GetStatus((ANSC_HANDLE)pMyObject) )
    {
        case  BBHM_IP_PING_STATUS_COMPLETE:

                pDslhDiagInfo->DiagnosticState = DSLH_DIAG_STATE_TYPE_Complete;

                break;

        case  BBHM_IP_PING_STATUS_ABORT:

                pDslhDiagInfo->DiagnosticState = DSLH_DIAG_STATE_TYPE_PING_Error_Internal;

                break;

        case  BBHM_IP_PING_STATUS_STOP:

                pDslhDiagInfo->DiagnosticState = DSLH_DIAG_STATE_TYPE_Complete;

                break;

        case  BBHM_IP_PING_STATUS_ERROR_HostName:

                pDslhDiagInfo->DiagnosticState = DSLH_DIAG_STATE_TYPE_Error_HostName;

                break;

        case  BBHM_IP_PING_STATUS_TIMEOUT:

                pMyObject->SetMaxRTT((ANSC_HANDLE)pMyObject, 0);
                pMyObject->SetMinRTT((ANSC_HANDLE)pMyObject, 0);
                pDslhDiagInfo->DiagnosticState = DSLH_DIAG_STATE_TYPE_Complete;

                break;

        default:

                return  returnStatus;
    }

    pMyObject->bResultQueryRunning     = FALSE;
    pDslhDiagInfo->SuccessCount        = nRead;
    pDslhDiagInfo->FailureCount        = pProperty->PktsSent - nRead;
    pDslhDiagInfo->AverageResponseTime = pProperty->AvgRTT;
    pDslhDiagInfo->MinimumResponseTime = pProperty->MinRTT;
    pDslhDiagInfo->MaximumResponseTime = pProperty->MaxRTT;

    return  returnStatus;
}
ANSC_STATUS
BbhmDiagnsRecv
    (
        ANSC_HANDLE                 hThisObject,
        ANSC_HANDLE                 hXsinkObject,
        PVOID                       buffer,
        ULONG                       ulSize
    )
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PBBHM_DIAG_NS_LOOKUP_OBJECT     pMyObject    = (PBBHM_DIAG_NS_LOOKUP_OBJECT )hThisObject;
    PBBHM_NS_LOOKUP_PROPERTY        pProperty    = (PBBHM_NS_LOOKUP_PROPERTY    )&pMyObject->Property;
    PBBHM_NS_LOOKUP_TDO_OBJECT      pStateTimer  = (PBBHM_NS_LOOKUP_TDO_OBJECT  )pMyObject->hStateTimer;
    PBBHM_NS_LOOKUP_XSINK_OBJECT    pXsink       = (PBBHM_NS_LOOKUP_XSINK_OBJECT)hXsinkObject;
    PANSC_XSOCKET_OBJECT            pXsocket     = (PANSC_XSOCKET_OBJECT        )pXsink->GetXsocket((ANSC_HANDLE)pXsink);
    PDSLH_NSLOOKUP_INFO             pDiagInfo    = (PDSLH_NSLOOKUP_INFO         )pMyObject->hDslhDiagInfo;
    PDNS_HEADER                     pDnsHeader   = (PDNS_HEADER)buffer;
    PBBHM_NS_LOOKUP_ECHO_ENTRY      pEchoEntry   = NULL;
    PBBHM_NS_LOOKUP_QUERY_ENTRY     pQuery       = NULL;
    ULONG                           StopTime     = 0;
    PSINGLE_LINK_ENTRY              pSLinkEntry  = NULL;
    char*                           p            = NULL;

    StopTime = AnscGetTickInMilliSeconds();


    if ( pProperty->Status != BBHM_NS_LOOKUP_STATUS_RUNNING )
    {
        return  ANSC_STATUS_UNAPPLICABLE;
    }

    /* Temporarily disable this check since we will check pQuery later */
/*
    if ( pXsocket->PeerAddress.Value != pProperty->DstIp.Value )
    {
        return  ANSC_STATUS_FAILURE;
    }
*/

    pQuery = pMyObject->GetPqueryById(pMyObject, AnscDnsGetId(pDnsHeader));
    if ( pQuery )
    {
        if ( AnscDnsGetRcode(pDnsHeader) != 0 )
        {
            if ( AnscDnsGetRcode(pDnsHeader) == DNS_RCODE_NAME_ERROR )
            {
                p = pDiagInfo->HostName + AnscSizeOfString(pDiagInfo->HostName) + 1;

                if ( AnscSizeOfString(p) )
                {
                    if ( !AnscEqualString(p - AnscSizeOfString(p) - 1, p, TRUE) )
                    {
                        pStateTimer->Stop((ANSC_HANDLE)pStateTimer);
                        pProperty->Control = BBHM_NS_LOOKUP_CONTROL_STOP;
                        pMyObject->DelAllPqueries(hThisObject);
                        pMyObject->PopEchoEntry(hThisObject);
                        pMyObject->ResetPropertyCounter(hThisObject);

                        *(p - 1) = '.';
                        pMyObject->SetControl   ((ANSC_HANDLE)pMyObject, BBHM_NS_LOOKUP_CONTROL_START);
                        BbhmDiageoStartDiag     ((ANSC_HANDLE)pMyObject);
                        return  ANSC_STATUS_SUCCESS;
                    }
                }
            }


            pSLinkEntry = AnscSListGetFirstEntry(&pMyObject->EchoTable);

            while ( pSLinkEntry )
            {
                pEchoEntry  = ACCESS_BBHM_NS_LOOKUP_ECHO_ENTRY(pSLinkEntry);
                pSLinkEntry = AnscSListGetNextEntry(pSLinkEntry);

                if ( pQuery->QueryId == pEchoEntry->QueryId )
                {
                    break;
                }
            }

            if ( AnscDnsGetRcode(pDnsHeader) == DNS_RCODE_NAME_ERROR )
            {
                pEchoEntry->Status = BBHM_NS_LOOKUP_STATUS_Error_HostNameNotResolved;
            }
            else if ( AnscDnsGetRcode(pDnsHeader) == DNS_RCODE_SERVER_FAILURE ||  AnscDnsGetRcode(pDnsHeader) == DNS_RCODE_REFUSED )
            {
                pEchoEntry->Status = BBHM_NS_LOOKUP_STATUS_Error_DNSServerNotAvailable;
            }
            else
            {
                pEchoEntry->Status = BBHM_NS_LOOKUP_STATUS_Error_Other;
            }
            pEchoEntry->AnswerType = AnscDnsIsAuthoritativeAnswer(pDnsHeader) ? BBHM_NS_LOOKUP_RESULT_Authoritative : BBHM_NS_LOOKUP_RESULT_NonAuthoritative;
            pEchoEntry->HostNameReturned = NULL;
            pEchoEntry->IPAddresses = NULL;
            pMyObject->DelPquery(pMyObject, pQuery);

            pProperty->PktsRecv++;
        }
        else
        {
            returnStatus = pMyObject->SetStopTime((ANSC_HANDLE)pMyObject, pQuery, pDnsHeader, StopTime);

            if ( returnStatus == ANSC_STATUS_SUCCESS )
            {
                pProperty->PktsRecv++;
            }
        }

        if ( pProperty->PktsRecv == pProperty->NumPkts )
        {
            pMyObject->SetStatus((ANSC_HANDLE)pMyObject, BBHM_NS_LOOKUP_STATUS_COMPLETE);
            pMyObject->Stop((ANSC_HANDLE)pMyObject);
        }

        return  returnStatus;
    }

    return  ANSC_STATUS_SUCCESS;
}
void
AnscTraceIpPacket
    (
        ANSC_HANDLE                 hIpPacket
    )
{
    ANSC_STATUS                     returnStatus        = ANSC_STATUS_SUCCESS;
    PIPV4_HEADER                    pIp4Header          = (PIPV4_HEADER)hIpPacket;
    PUDP_HEADER                     pUdpHeader          = (PUDP_HEADER)AnscIpv4GetPayload(pIp4Header);
    PTCP_HEADER                     pTcpHeader          = (PTCP_HEADER)pUdpHeader;
    PICMPV4_HEADER                  pIcmpHeader;

    PUCHAR                          pTpPayload;
    ULONG                           ulTpPayloadLen;
    char                            TcpFlagStr[7]       = "      \0";

    ULONG                           ulTimeStamp;
    ULONG                           seconds;
    ULONG                           mSeconds;

    ULONG                           currentOffset       = 0;
    ULONG                           ulFragmentSize      = 0;

    /*
     *  get current time
     */
    ulTimeStamp = AnscGetTickInMilliSeconds();

    seconds     = ulTimeStamp;
    mSeconds    = ulTimeStamp % 1000;

    /*
     *  print the packet
     */
    AnscTraceWrapper
        (
            "%u.%03u IP: len = %d, ",
            seconds,
            mSeconds,
            AnscIpv4GetTotalLength(pIp4Header)
        );

    pIcmpHeader  = (PICMPV4_HEADER)pUdpHeader;

    if ( !AnscIpv4IsFragment(pIp4Header) || (AnscIpv4IsFragment(pIp4Header) && AnscIpv4IsFirstFragment(pIp4Header)))
    {
        if(AnscIpv4GetTransportType(pIp4Header) == TCP_TRANSPORT)
        {
            AnscTraceWrapper
                (
                    "protocol=%d, src=%d.%d.%d.%d:%d, dest=%d.%d.%d.%d:%d ",
                    AnscIpv4GetTransportType(pIp4Header),
                    AnscIpv4GetSrcAddressDot(pIp4Header)[0],
                    AnscIpv4GetSrcAddressDot(pIp4Header)[1],
                    AnscIpv4GetSrcAddressDot(pIp4Header)[2],
                    AnscIpv4GetSrcAddressDot(pIp4Header)[3],
                    AnscTcpGetSrcPort(pTcpHeader),
                    AnscIpv4GetDstAddressDot(pIp4Header)[0],
                    AnscIpv4GetDstAddressDot(pIp4Header)[1],
                    AnscIpv4GetDstAddressDot(pIp4Header)[2],
                    AnscIpv4GetDstAddressDot(pIp4Header)[3],
                    AnscTcpGetDstPort(pTcpHeader)
                );

            if (AnscTcpIsUrg(pTcpHeader))
            {
                TcpFlagStr[0] = 'U';
            }
            if (AnscTcpIsAck(pTcpHeader))
            {
                TcpFlagStr[1] = 'A';
            }
            if (AnscTcpIsPsh(pTcpHeader))
            {
                TcpFlagStr[2] = 'P';
            }
            if (AnscTcpIsRst(pTcpHeader))
            {
                TcpFlagStr[3] = 'R';
            }
            if (AnscTcpIsSyn(pTcpHeader))
            {
                TcpFlagStr[4] = 'S';
            }
            if (AnscTcpIsFin(pTcpHeader))
            {
                TcpFlagStr[5] = 'F';
            }
            TcpFlagStr[6] = 0;

            AnscTraceWrapper
                (
                    " %s ",
                    TcpFlagStr
                );

            pTpPayload      = AnscTcpGetPayload(pTcpHeader);
            ulTpPayloadLen  = AnscIpv4GetTotalLength(pIp4Header) - ((ULONG)pTpPayload - (ULONG)pIp4Header);

            AnscTraceWrapper
                (
                    "Seq=%u~%u, Ack=%u",
                    AnscTcpGetSeqNumber(pTcpHeader),
                    AnscTcpGetSeqNumber(pTcpHeader) + ulTpPayloadLen,
                    AnscTcpGetAckNumber(pTcpHeader)
                );
        }
        else if (AnscIpv4GetTransportType(pIp4Header) == UDP_TRANSPORT)
        {
            AnscTraceWrapper
                (
                    "protocol=%d, src=%d.%d.%d.%d:%d, dest=%d.%d.%d.%d:%d",
                    AnscIpv4GetTransportType(pIp4Header),
                    AnscIpv4GetSrcAddressDot(pIp4Header)[0],
                    AnscIpv4GetSrcAddressDot(pIp4Header)[1],
                    AnscIpv4GetSrcAddressDot(pIp4Header)[2],
                    AnscIpv4GetSrcAddressDot(pIp4Header)[3],
                    AnscUdpGetSrcPort(pUdpHeader),
                    AnscIpv4GetDstAddressDot(pIp4Header)[0],
                    AnscIpv4GetDstAddressDot(pIp4Header)[1],
                    AnscIpv4GetDstAddressDot(pIp4Header)[2],
                    AnscIpv4GetDstAddressDot(pIp4Header)[3],
                    AnscUdpGetDstPort(pUdpHeader)
                );
        }
        else if (AnscIpv4GetTransportType(pIp4Header) == ICMP_TRANSPORT)
        {
            AnscTraceWrapper
                (
                    "protocol=%d, src=%d.%d.%d.%d, dest=%d.%d.%d.%d, type=%d",
                    AnscIpv4GetTransportType(pIp4Header),
                    AnscIpv4GetSrcAddressDot(pIp4Header)[0],
                    AnscIpv4GetSrcAddressDot(pIp4Header)[1],
                    AnscIpv4GetSrcAddressDot(pIp4Header)[2],
                    AnscIpv4GetSrcAddressDot(pIp4Header)[3],
                    AnscIpv4GetDstAddressDot(pIp4Header)[0],
                    AnscIpv4GetDstAddressDot(pIp4Header)[1],
                    AnscIpv4GetDstAddressDot(pIp4Header)[2],
                    AnscIpv4GetDstAddressDot(pIp4Header)[3],
                    AnscIcmpv4GetType(pIcmpHeader)
                );
        }
        else
        {
            AnscTraceWrapper
                (
                    "protocol=%d, src=%d.%d.%d.%d, dest=%d.%d.%d.%d",
                    AnscIpv4GetTransportType(pIp4Header),
                    AnscIpv4GetSrcAddressDot(pIp4Header)[0],
                    AnscIpv4GetSrcAddressDot(pIp4Header)[1],
                    AnscIpv4GetSrcAddressDot(pIp4Header)[2],
                    AnscIpv4GetSrcAddressDot(pIp4Header)[3],
                    AnscIpv4GetDstAddressDot(pIp4Header)[0],
                    AnscIpv4GetDstAddressDot(pIp4Header)[1],
                    AnscIpv4GetDstAddressDot(pIp4Header)[2],
                    AnscIpv4GetDstAddressDot(pIp4Header)[3]
                );
        }
    }
    else
    {
        AnscTraceWrapper
            (
                "IP: protocol=%d, src=%d.%d.%d.%d, dest=%d.%d.%d.%d ",
                AnscIpv4GetTransportType(pIp4Header),
                AnscIpv4GetSrcAddressDot(pIp4Header)[0],
                AnscIpv4GetSrcAddressDot(pIp4Header)[1],
                AnscIpv4GetSrcAddressDot(pIp4Header)[2],
                AnscIpv4GetSrcAddressDot(pIp4Header)[3],
                AnscIpv4GetDstAddressDot(pIp4Header)[0],
                AnscIpv4GetDstAddressDot(pIp4Header)[1],
                AnscIpv4GetDstAddressDot(pIp4Header)[2],
                AnscIpv4GetDstAddressDot(pIp4Header)[3]
            );
    }

    if ( AnscIpv4GetTos(pIp4Header) != 0 )
    {
        AnscTraceWrapper(" Tos=0x%X", AnscIpv4GetTos(pIp4Header));
    }

    if ( AnscIpv4IsDontFragment(pIp4Header) )
    {
        AnscTraceWrapper(" DF");
    }

    AnscTraceWrapper(" TTL=%lu", AnscIpv4GetTtl(pIp4Header));

    if (!AnscIpv4IsFragment(pIp4Header))
    {
        AnscTraceWrapper("\n");
    }
    else
    {
        currentOffset       = AnscIpv4GetFragmentOffset(pIp4Header) * 8;
        ulFragmentSize      = (ULONG)AnscIpv4GetTotalLength(pIp4Header) - AnscIpv4GetHeaderSize(pIp4Header);

        AnscTraceWrapper
            (
                " id = %X, %d@%d\n",
                AnscIpv4GetId(pIp4Header),
                (int)ulFragmentSize,
                (int)currentOffset
            );
    }

    return;
}