ANSC_STATUS
BbhmDiagipSetStopTime
    (
        ANSC_HANDLE                 hThisObject,
        USHORT                      SeqNumber,
        ULONG                       PktSize,
        UCHAR                       TTL,
        ULONG                       StopTime
    )
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_FAILURE;
    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;
    PSINGLE_LINK_ENTRY              pSLinkEntry  = NULL;
    PBBHM_IP_PING_ECHO_ENTRY        pEchoEntry   = NULL;
    PBBHM_IP_PING_ECHO_ENTRY        pMEchoEntry  = NULL;
    ULONG                           ulHashIndex  = SeqNumber % MAX_ECHO_TABLE_SIZE;

    AnscAcquireLock(&pMyObject->EchoTableLock);
    pSLinkEntry = AnscSListGetFirstEntry(&pMyObject->EchoTable[ulHashIndex]);

    while ( pSLinkEntry )
    {
        pEchoEntry = (PBBHM_IP_PING_ECHO_ENTRY)ACCESS_BBHM_IP_PING_ECHO_ENTRY(pSLinkEntry);
        pSLinkEntry = AnscSListGetNextEntry(pSLinkEntry);

        if ( pEchoEntry->SeqId == SeqNumber )
        {
            if ( (StopTime - pEchoEntry->StartTime <= pProperty->TimeOut) && (pEchoEntry->StopTime == 0) )
            {
                returnStatus = ANSC_STATUS_SUCCESS;
                pEchoEntry->StopTime    = StopTime;
                pEchoEntry->TTL         = TTL;
                pEchoEntry->PktSize     = PktSize;
                pEchoEntry->ICMPType    = 0;
                pMEchoEntry = (PBBHM_IP_PING_ECHO_ENTRY)AnscAllocateMemory(sizeof(BBHM_IP_PING_ECHO_ENTRY));
                if ( pMEchoEntry )
                {
                    pMEchoEntry->StartTime = pEchoEntry->StartTime;
                    pMEchoEntry->StopTime  = pEchoEntry->StopTime;
                    pMEchoEntry->SeqId     = pEchoEntry->SeqId;
                    pMEchoEntry->PktSize   = pEchoEntry->PktSize;
                    pMEchoEntry->TTL       = pEchoEntry->TTL;
                    pMEchoEntry->ICMPType  = pEchoEntry->ICMPType;
                    AnscAcquireLock(&pMyObject->MiddleResultLock);
                    AnscSListPushEntryAtBack(&pMyObject->MiddleResult, &pMEchoEntry->Linkage);
                    AnscReleaseLock(&pMyObject->MiddleResultLock);
                }
            }

            break;
        }
    }

    AnscReleaseLock(&pMyObject->EchoTableLock);

    return  returnStatus;
}
/**********************************************************************

    caller:     owner of this object

    prototype:

        void
        AnscAsn1AddAttribute
            (
                ANSC_HANDLE                 hThisObject,
                PANSC_ATTR_OBJECT           pAttrObject,
                BOOLEAN                     bAppend
            );

    description:

        This function add a new attribute object.

    argument:   ANSC_HANDLE                 hThisObject
                This handle is actually the pointer of this object
                itself.

                PANSC_ATTR_OBJECT           pAttrObject,
                The new attribute object will be added;

                BOOLEAN                     bAppend
                Add to the first or append at the last

    return:     the first encoding octet;

**********************************************************************/
void
AnscAsn1AddAttribute
    (
        ANSC_HANDLE                 hThisObject,
        PANSC_ATTR_OBJECT           pAttrObject,
        BOOLEAN                     bAppend
    )
{
    PANSC_ASN1_OBJECT               pMyObject    = (PANSC_ASN1_OBJECT)hThisObject;

#if 0
    PANSC_ATTR_OBJECT               pAttr;
    PSINGLE_LINK_ENTRY              pSListEntry;
#endif

    if( hThisObject == NULL || pAttrObject == NULL)
    {
        return;
    }

    if( bAppend)
    {
        AnscSListPushEntryAtBack(&pMyObject->sAttrList, &pAttrObject->Linkage);
    }
    else
    {
#if 0
        /*
         *  Check if this attribute already exists, ignore the new one.
         */
        pSListEntry =   AnscSListGetFirstEntry(&pMyObject->sAttrList);

        if( pSListEntry != NULL)
        {
            pAttr       = ACCESS_ANSC_ATTR_OBJECT(pSListEntry);

            if( pAttrObject->EqualsTo(pAttrObject, pAttr))
            {
                return;
            }
        }
#endif
        AnscSListPushEntry(&pMyObject->sAttrList, &pAttrObject->Linkage);
    }
}
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;
}
/**************************************************************************************
 *
 *  static callback functions to get cert and key info from PKCS12.
 *
 **************************************************************************************/
ANSC_STATUS
initProc
    (
        ANSC_HANDLE                 hContext,
        PUCHAR                      pCertEncoding,
        ULONG                       ulCertSize,
        PUCHAR                      pKeyEncoding,
        ULONG                       ulKeyInfoSize
    )
{
    PPKI_CLIENT_ENTITY              pThisObject  = (PPKI_CLIENT_ENTITY)hContext;
    PALCERT_CONTEXT                 pCertContext = NULL;
    PANSC_ASN1_CERTIFICATE          pNewCert;
    PUCHAR                          pEncoding;

    if( pCertEncoding == NULL || ulCertSize == 0)
    {
        return ANSC_STATUS_FAILURE;
    }

    pCertContext = (PALCERT_CONTEXT)pThisObject->hContainerContext;

    if( pKeyEncoding == NULL || ulKeyInfoSize == 0)
    {
        /* add the ca cert */
        if( pCertContext == NULL)
        {
            pNewCert = (PANSC_ASN1_CERTIFICATE)AnscAsn1CreateCertificate(NULL);

            pEncoding= pCertEncoding;

            pNewCert->DecodingData(pNewCert,(PVOID*)&pEncoding);

            AnscSListPushEntryAtBack(&pThisObject->sCAList, &pNewCert->Linkage);
        }
        else
        {
            pCertContext->AddTrustedCA
                (
                    pCertContext,
                    "",
                    pCertEncoding,
                    ulCertSize
                );
        }
    }
    else
    {
        pThisObject->SetIssuedCert(pThisObject, pCertEncoding, ulCertSize);
        pThisObject->SetPrivateKeyInfo(pThisObject, pKeyEncoding, ulKeyInfoSize);
    }

    if( pThisObject->pCertAttr != NULL)
    {
        pThisObject->pCertAttr->Remove(pThisObject->pCertAttr);
    }

    pThisObject->pCertAttr = GenerateAttrByCertificate(pThisObject->hUserCert);

    return ANSC_STATUS_SUCCESS;
}
ANSC_STATUS
AdvPKIEntitySetIssuedPKCS7Certs
    (
        ANSC_HANDLE                 hThisObject,
        PUCHAR                      pEncoding,
        ULONG                       length
    )
{

    PPKI_CLIENT_ENTITY              pThisObject  = (PPKI_CLIENT_ENTITY)hThisObject;
    PUCHAR                          pBack        = pEncoding;
    PANSC_ASN1_CONTENTINFO          pInfo        = NULL;
    PANSC_ASN1_SIGNEDDATA           pSignedData;
    PANSC_ASN1_CERTIFICATE          pCert, pCloned;
    ANSC_STATUS                     retStatus    = ANSC_STATUS_SUCCESS;
    ULONG                           count,i;
    BOOL                            bFound       = FALSE;
    ANSC_CRYPTO_PUB_KEY_GEN_PARAMS  genParams;
    PKI_KEY_TYPE                    keyType;
    PALCERT_CONTEXT                 pCertContext = NULL;
    PUCHAR                          pCertEncoding;
    ULONG                           certLength;

    if( hThisObject == NULL || pEncoding == NULL || length <= 8)
    {
        return ANSC_STATUS_FAILURE;
    }

    if(!AnscCheckAsn1Validity(pEncoding, length))
    {
        AnscTrace("Invalid ASN1 encoding.\n");

        return ANSC_ASN1_INVALID_ENCODE_LENGTH;
    }

    /* create the content info and decode from the encoding */
    pInfo = (PANSC_ASN1_CONTENTINFO)AnscAsn1CreateContentInfo(NULL);

    if( pInfo == NULL)
    {
        return ANSC_STATUS_FAILURE;
    }

    retStatus = 
        pInfo->DecodingData(pInfo, (PVOID*)&pBack);

    if( retStatus != ANSC_STATUS_SUCCESS)
    {
        goto EXIT;
    }

    /* get the signed data */
    pSignedData = (PANSC_ASN1_SIGNEDDATA)
        pInfo->GetSignedData(pInfo);

    if( pSignedData == NULL)
    {
        retStatus = ANSC_STATUS_FAILURE;

        goto EXIT;
    }

    /* get the certificate */
    count = pSignedData->GetTotalCerts(pSignedData);

    if( count == 0)
    {
        retStatus = ANSC_STATUS_FAILURE;

        goto EXIT;
    }

    /* add the certificate one by one */
    pThisObject->GetPublicKeyInfo
        (
            pThisObject,
            &keyType,
            &genParams
        );

    pCertContext = (PALCERT_CONTEXT)pThisObject->hContainerContext;

    for( i = 0; i < count; i ++)
    {
        pCert = (PANSC_ASN1_CERTIFICATE)
            pSignedData->GetCertificateByIndex(pSignedData, i);

        if( pCert != NULL)
        {
            pCloned = (PANSC_ASN1_CERTIFICATE)pCert->Clone(pCert);

            if( pCloned == NULL)
            {   
                retStatus = ANSC_STATUS_RESOURCES;

                goto EXIT;
            }

            if( bFound == FALSE &&
                pCert->IsKeyMatching
                    (
                        pCert,
                        keyType,
                        &genParams
                    )
              )
            {
                /* remove the old one */
                if( pThisObject->hUserCert != NULL)
                {
                    ((PANSC_ASN1_OBJECT)pThisObject->hUserCert)->AsnFree(pThisObject->hUserCert);
                }
                
                if( pThisObject->pCertEncoding != NULL)
                {
                    AnscFreeMemory(pThisObject->pCertEncoding);
                }

                /* set the new one and copy the encoding */
                pThisObject->hUserCert      = pCloned;
                pThisObject->pCertEncoding  =
                    pCloned->GetEncodedData
                        (
                            pCloned,
                            &pThisObject->uLength
                        );

                bFound = TRUE;
            }
            else
            {
                if( pCertContext == NULL)
                {
                    AnscSListPushEntryAtBack(&pThisObject->sCAList, &pCloned->Linkage);
                }
                else
                {
                    pCertEncoding = pCloned->GetEncodedData(pCloned, &certLength);

                    pCloned->AsnFree(pCloned);

                    pCertContext->AddTrustedCA
                        (
                            pCertContext,
                            "",
                            pCertEncoding,
                            certLength
                        );

                    AnscFreeMemory(pCertEncoding);
                }
            }
        }
    }    

EXIT:

    if( pInfo != NULL)
    {
        pInfo->AsnFree(pInfo);
    }

    return retStatus;
}