• AVR Freaks

Hot!Harmony IGMP permanently discards query report nodes

Author
K_Larsen
New Member
  • Total Posts : 3
  • Reward points : 0
  • Joined: 2014/07/21 01:24:29
  • Location: 0
  • Status: offline
2019/02/07 05:38:14 (permalink)
0

Harmony IGMP permanently discards query report nodes

Harmony IGMP permanently discards query report nodes from igmpGenQueryReportPool and igmpGroupQueryReportPool making it unable to respond to queries.

The problem was discovered in Harmony v2.06 however, the problem exists in previous versions as well.

The _IGMP_ProcessV3Query function used _IGMP_FindScheduledQueryReport to find existing query reports to update or reuse instead of generating a new report.
The problem is that _IGMP_FindScheduledQueryReport is set to remove the found node from the list returning the only remaining reference to the _IGMP_ProcessV3Query function.
If the IGMP_ProcessV3Query function then determines to use the found node due to rule #1, the function returns without further processing leaving the found node detached from all lists.
The same problem will occur for rule #4 and #5.
 
Possible solution to this problem is to change the _IGMP_ProcessV3Query function so it sets the “remove” parameter to “false” when calling the _IGMP_FindScheduledQueryReport function.
An additional change is required as the _IGMP_ScheduleGenQueryReport function in rule #2 adds the node to the igmpGenQueryReportList (the found node is already in this list) thus creating a circular reference.
Either update the found node without re-adding it to the list or remove it from the list prior to calling the _IGMP_ScheduleGenQueryReport function.
 
Finally rule #5 does not update the transmit timestamp when required (tReport < pGsq->tTransmit).
 
The following code snippet contains a modified version of the _IGMP_ProcessV3Query function with a possible solution to the problem.
static void _IGMP_ProcessV3Query(TCPIP_IGMPv3_QUERY_MESSAGE* pQuery, int ifIx)
{
    TCPIP_IGMP_QUERY_TYPE qType;
    uint32_t maxRespTime, tReport;
    TCPIP_IGMP_RESP_CODE_FLOAT rCodeFloat;
    TCPIP_IGMP_GEN_QUERY_REPORT_NODE* pGq;
    TCPIP_IGMP_GROUP_QUERY_REPORT_NODE *pGsq;
    IPV4_ADDR groupAddress;
    TCPIP_IGMP_GROUP_SOURCE_ADDRESSES newReqSources, unionSources;
    uint16_t nSources = 0;

    igmpRobustnessVar = pQuery->qrv < TCPIP_IGMP_ROBUSTNESS_LOW_LIMIT ? TCPIP_IGMP_ROBUSTNESS_VARIABLE : pQuery->qrv;
    
    if((groupAddress.Val = pQuery->groupAddress) == 0)
    {
        qType = TCPIP_IGMP_QUERY_GENERAL;
    }
    else
    {
        if(pQuery->nSources == 0)
        {
            qType = TCPIP_IGMP_QUERY_GROUP_SPEC;
        }
        else
        {
            qType = TCPIP_IGMP_QUERY_GROUP_SOURCE_SPEC;
            nSources = TCPIP_Helper_ntohs(pQuery->nSources);
        }
    }

    // calculate maxRespTime in milliseconds
    if(pQuery->maxRespCode < TCPIP_IGMP_MAX_RESP_CODE_LIMIT)
    {
        maxRespTime = pQuery->maxRespCode * 100;
    }
    else
    {
        rCodeFloat.val = pQuery->maxRespCode;
        maxRespTime = ((rCodeFloat.mant | 0x10) << (rCodeFloat.exp + 3)) * 100;
    }

    tReport = SYS_TMR_TickCountGet() + (SYS_RANDOM_PseudoGet() % maxRespTime) * SYS_TMR_TickCounterFrequencyGet() / 1000;

    igmpListsLock();
    pGq = (TCPIP_IGMP_GEN_QUERY_REPORT_NODE*)_IGMP_FindScheduledQueryReport(TCPIP_IGMP_QUERY_GENERAL, 0, ifIx, false);
    igmpListsUnlock();

    // check the current status report rules
    // #1 rule: check for existing GQ scheduled earlier
    if(pGq != 0 && pGq->tTransmit < tReport)
    {
       return;
    }

    // #2 rule: if a GQ was received, schedule it and cancel a previous GQ
    if(qType == TCPIP_IGMP_QUERY_GENERAL)
    {
        if(pGq == 0)
        { // couldn't find an old GQ report
            pGq = (TCPIP_IGMP_GEN_QUERY_REPORT_NODE*)_IGMP_GetNewQueryReport(TCPIP_IGMP_QUERY_GENERAL);
        }
        else
        {
            igmpListsLock();
            TCPIP_Helper_SingleListNodeRemove(&igmpGenQueryReportList, (SGL_LIST_NODE *) pGq);
            igmpListsUnlock();
        }

        if(pGq != 0)
        { // prepare the GQ report and schedule it;
            _IGMP_ScheduleGenQueryReport(pGq, ifIx, tReport);
        }
        else
        { // couldn't find a slot for the new GQ report; should NOT happen!
            _IGMPAssertCond(true, __func__, __LINE__);
            _IGMP_ReportEvent(groupAddress, TCPIP_IGMP_EVENT_GET_GEN_QUERY_REPORT_ERROR);
        }
        return;
    }

    // #3 rule: GSQ or GSSQ received; if no pending response, then schedule a group report
    igmpListsLock();
    pGsq = (TCPIP_IGMP_GROUP_QUERY_REPORT_NODE*)_IGMP_FindScheduledQueryReport(TCPIP_IGMP_QUERY_GROUP_SPEC, groupAddress.Val, ifIx, false);
    igmpListsUnlock();
    if(pGsq == 0)
    {
        pGsq = (TCPIP_IGMP_GROUP_QUERY_REPORT_NODE*)_IGMP_GetNewQueryReport(qType);
        if(pGsq != 0)
        {
            _IGMP_InitGroupQueryReport(pGsq, groupAddress, ifIx, tReport);
            _IGMP_SourceScheduleGroupQueryReport(pGsq, nSources, pQuery->sources);
        }
        else
        { // couldn't find a slot for the new group report
            _IGMPDebugCond(true, __func__, __LINE__);
            _IGMP_ReportEvent(groupAddress, TCPIP_IGMP_EVENT_GET_GROUP_QUERY_REPORT_ERROR);
        }
        return;
    }

    // #4 rule: if GSQ received or pending GSQ, then schedule a GSQ
    if(qType == TCPIP_IGMP_QUERY_GROUP_SPEC || pGsq->qSources[0].repSources.nSources == 0)
    {
        pGsq->qSources[0].repSources.nSources = 0; // clear old pending sources
        if(tReport < pGsq->tTransmit)
        {
            pGsq->tTransmit = tReport;
        }
        return;
    }

    // #5 rule: GSSQ received and pending GSSQ, then schedule an augumented GSSQ
    if(tReport < pGsq->tTransmit)
    {
        pGsq->tTransmit = tReport;
    }
    newReqSources.nSources = nSources;
    memcpy(&newReqSources, pQuery->sources, nSources * sizeof(newReqSources.sourceAddresses[0]));
    
    _IGMP_UnionSources(&newReqSources, &pGsq->qSources[0].repSources, &unionSources);
    _IGMP_SourceScheduleGroupQueryReport(pGsq, unionSources.nSources, unionSources.sourceAddresses);
    

}

The code can be optimize but I opted not to do so in order to make comparison with the original code easier.
#1
rainad
Moderator
  • Total Posts : 1149
  • Reward points : 0
  • Joined: 2009/05/01 13:39:25
  • Location: 0
  • Status: online
Re: Harmony IGMP permanently discards query report nodes 2019/02/07 07:46:00 (permalink)
0
Thank you for finding and reporting this. We'll run some tests and create an internal issue to be solved ASAP.
 
 
#2
Jump to:
© 2019 APG vNext Commercial Version 4.5