This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C129XNCZAD: How Can I detect IP conflict on the network

Part Number: TM4C129XNCZAD

I have NDK version ndk_2_25_00_09 and want to detect IP conflicts on the network to decide to stop the Stack to normalize the network behavior and improve the accessibility for each node

by detecting a conflict I mean detecting that another machine or Mac address has the same IP on the network so 

1. the first approach

during startup, I attempted to ping on my local IP, and if the ping success continue normal operation, and If failed stop the NDK stack but

- when my ethernet cable is not connected to the device ping request succeeded even though I am not actually on the network so, in this case, I am pinging myself and in this case, actually I notice that the device not forwarding ping requests on the network - even on my PC when pinging myself I don't see ICMP packets on wireshark but when I ping another IP I see the ICMP packets out on the Ethernet Connection
- also when the cable is connected to my (switch or router) and my ip exists on the network before, (Conflict case that I want to detect) the device failed to ping its IP as it is not receiving its own ICMP packet so I got ping failure of ICMP request timeout and sometimes this case is validated and I got a success if I started the device then started the conflicted device so according to the first node connected to the Ethernet bus it will be validated but actually take the decision of disabling the network according to ping failure or not is not sufficient as it may be many cases one of them is the conflict 

2. second approach 

I used the arp table to check if my local IP exists on the cached arp entries or not and if exists so there is a conflict and if not then there is no conflict but

- this table is cached so what if the node exists on the bus but is never registered on my local arp cache as the arp table is only filled with arp packet reception which is triggered during communication only so 
what if the device is configured and initialized on the stack but never sent a request to another node so this node doesn't have an ip entry of this node and attempts to change its own IP to the other ip node on the bus?


so is there a way inside the NDK to detect a conflict or a methodology that I can follow to detect the conflict without affection or violating any protocol rules?

  • Hi,

      I don't think there is a build-in APIs or methods in NDK to detect IP conflicts. You will need to detect the conflict as part of the application. After some Google searches, I think what you are doing is on the right path - your second approach seems to be suggested in various articles. Perhaps, you can combine both your approach 1 and 2. Below are some of the articles with suggestions on how to detect IP conflicts. You can do more searches on your own. 

    https://www.dnsstuff.com/ip-address-conflict#:~:text=The%20best%20way%20to%20avoid,addresses%20from%20your%20core%20devices.

    https://documentation.its.umich.edu/node/523

    https://www.auvik.com/franklyit/blog/how-to-fix-ip-address-conflicts/

  • thanks, Charles

    these articles were really helpfull and I depend on these functions from TI stack

    - the read arp packets using arp hook during NDK boot (only)
    - concmping I modified this function alittle bit to refactor it and to fit in my app

    first senario is when my node is statically configured with an IP already on the network

    - the NDK boot task in nature sends an ARP Broadcasting message announcing itself on the network so if this node already exists (conflict)
    the remote node rely with its mac address which is different than the current node mac so during boot task we set an ARP hook and read the received messages and if we received our configured IP as source sender with different MAC that is considered as a conflict and we take action for me I disable the stack, but you can disable the interface and check it periodically

    for this approach I used there code snippets

    LLI_setARPHook(fxnARPCallback); //to set the arp hook before starting (booting) the stack
    
    do
    {
        rc= NC_NetStart(hCfgIpAddr,\
        SoAd_vNetworkOpenHook,\
        SoAd_vNetworkCloseHook,\
        SoAd_vNetworkIPAddressChangeHook);
    }while(rc> 0);


    and for the hook itself 

    void fxnARPCallback(void* data)
    {
        ARPHDR* ARPPacketHDR;
        ARPPacketHDR = (ARPHDR*)( ((INT8U*)data) + 14U);
    
        if( memcmp((ARPPacketHDR->IPSrc),&(SoAd_objstrDCFGType.objstrIPSettings.u32LocalIP), (INT32U) 4U ) == 0U)
        {
            if( memcmp((ARPPacketHDR->SrcAddr), SoAd_objstrDCFGType.objstrIPSettings.u8MACAdressArray, (INT32U) 6U) != 0U)
            {
                /*conflict is detected */
            }
        }
    }



    then to detech conflcit upon changing the IP by removing and adding ip entries before doing such thing we need to ping this new IP if it is not pinging then the ip is not used and we can change our IP configuration if pings successfully then the ip is used and replying to me and log a message with conflcit detected too at runtime Star 

    my version of ping function was like the following
    INT8 SoAd_Ping( IPN *IPAddr, INT8S s8Attempts )
    {
        fd_set              ibits;
        INT32S              cc,fromlen;
        UINT16              cnt_send=0, cnt_recv=0;     /* Packets send and received */
        SOCKET              s;                          /* ICMP socket file descriptor */
        struct  sockaddr_in to;                         /* who to ping */
        struct  sockaddr_in from;                       /* who replied */
        static INT8S        pBuf[30] = {0};
        struct  timeval     timeout;                    /* Timeout struct for select */
        INT32U              timestart;
    
        INT8S               retCode;
        INT8U               SucessAttempts;
    
        (void)fdOpenSession(TaskSelf());
        retCode = Ping_Success;
        SucessAttempts = 0U;
        /* Create the ICMP Socket */
        s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
        if( s == INVALID_SOCKET )
        {
            SoAd_vmLogError1(&objstrSoAdModuleInfoType, "failed socket create (%d)",fdError());
            retCode = Ping_INVALID_SOCKET;
        }
        /* Create to "to" address */
        bzero( &to, sizeof(struct sockaddr_in));
        to.sin_family       = AF_INET;
        to.sin_addr.s_addr  = *IPAddr;
        /* Create to "from" address */
        bzero( &from, sizeof(struct sockaddr_in));
        from.sin_family     = AF_INET;
        /* Set socket option to allow us to broadcast */
        cc = 1;
        if( setsockopt( s, SOL_SOCKET, SO_BROADCAST, &cc, sizeof(INT32S) ) < 0 )
        {
            SoAd_vmLogError1(&objstrSoAdModuleInfoType, "failed set IP broadcast (%d)",fdError());
            retCode = Ping_Failed_SetIPBroadcast;
        }
        /* Configure our timeout to be 0.5 seconds */
        timeout.tv_sec  = 0;
        timeout.tv_usec = 500000;
    
        SoAd_vmLogActivity5(&objstrSoAdModuleInfoType, "Pinging %d.%d.%d.%d with %d data bytes",\
                            (INT32U)(*IPAddr & 0xFFU),\
                            (INT32U)((*IPAddr >> 8)&0xFFU),\
                            (INT32U)((*IPAddr >> 16)&0xFFU),\
                            (INT32U)((*IPAddr >> 24)&0xFFU),\
                            PING_DATALEN );
        /* Ping loop */
        while( cnt_send < s8Attempts )
        {
            /* Use send count for sequence - starts at "1" */
            cnt_send++;
            memset(pBuf, 0x00, sizeof(char)*40);
            /* Build the ping packet */
            SoAd_BuildPing( pBuf, cnt_send );
            /* Get the time now */
            timestart = llTimerGetTime(0);
            cnt_recv = 0;
            /* Send the ping */
            cc = sendto( s, pBuf, PING_DATALEN, 0,(struct sockaddr *)&to, sizeof(to) );
            if( cc < 0 )
            {
                SoAd_vmLogError1(&objstrSoAdModuleInfoType, "failed sento (%d)",fdError());
            }
            else if( cc != PING_DATALEN )
            {
                SoAd_vmLogError0(&objstrSoAdModuleInfoType, "sento - partial write!");
            }
            else{
                while( (timestart+2) > llTimerGetTime(0) )
                {
                    /* Select for timeout period second */
                    FD_ZERO(&ibits);
                    FD_SET(s, &ibits);
                    if( fdSelect( (INT32S)s, &ibits, 0, 0, &timeout ) < 0 )
                    {
                        SoAd_vmLogError1(&objstrSoAdModuleInfoType, "failed select (%d)",fdError());
                        retCode = Ping_Failed_SelectSocket;
                        break;
                    }
                    /* Check for a reply */
                    if( FD_ISSET(s, &ibits) )
                    {
                        fromlen = sizeof(from);
                        cc = (INT32S)recvfrom( s, pBuf, PING_DATALEN, 0,(struct sockaddr *)&from, &fromlen );
                        if( cc < 0 )
                        {
                            SoAd_vmLogError1(&objstrSoAdModuleInfoType, "failed recvfrom (%d)",fdError());
                            retCode = Ping_Failed_recvfrom;
                            break;
                        }
                        /* Check the reply. Bump the recv count if good reply */
                        if( SoAd_CheckPing( pBuf, cnt_send, cc, IPAddr) )
                        {
                            SucessAttempts++;
                            cnt_recv++;
                            break;
                        }
                    }
                }
                /* If send is more than reply, then we missed a reply */
                if( !cnt_recv )
                {
                    SoAd_vmLogError0(&objstrSoAdModuleInfoType, "Reply timeout");
                    retCode = Ping_Reply_Timeout;
                }
            }
        }
    
        if(retCode == Ping_Success && SucessAttempts > s8Attempts/2)
        {
            retCode = Ping_Success;
        }
        else
        {
            /*do nothing*/
            retCode = Ping_Fail;
        }
    
        if( s != INVALID_SOCKET )
            fdClose( s );
    
        return retCode;
    }
    
    static INT8 SoAd_CheckPing( INT8S *ps8Buf,INT16U u16Seq,INT32S s32NumberOfBytes, IPN* ps8IpStr)
    {
        INT32S     ICMPLen;
        INT16U     Id,Seq;
        INT8U      retCode;
    
        retCode = Ping_SUCCESS_ECHOREPLY;
        /* Get header pointers */
    
        /* Get the total length of the ICMP message */
        ICMPLen = (uint)(HNC16( ((IPHDR *)ps8Buf)->TotalLen )) - ( (((IPHDR *)ps8Buf)->VerLen & 0xF) * 4 );
    
        /* Verify the ICMP type */
        if( ((ICMPHDR *)(ps8Buf+( (((IPHDR *)ps8Buf)->VerLen & 0xF) * 4 )))->Type != ICMP_ECHOREPLY )
            retCode = Ping_NOTICMP_ECHOREPLY ;
    
        /* Get the seq and the id */
        Seq = (INT32S)HNC16(((ICMPREQHDR *)((ICMPHDR *)(ps8Buf+( (((IPHDR *)ps8Buf)->VerLen & 0xF) * 4 )))->Data)->Seq);
        Id  = (INT32S)HNC16(((ICMPREQHDR *)((ICMPHDR *)(ps8Buf+( (((IPHDR *)ps8Buf)->VerLen & 0xF) * 4 )))->Data)->Id);
    
        /* If the reply is incorrect, don't continue */
        if( Id != PING_IDENTIFICATION || Seq != u16Seq )
        {
            SoAd_vmLogError4(&objstrSoAdModuleInfoType, "Non-matching echo reply from %d.%d.%d.%d", \
                             (INT32U)(*ps8IpStr & 0xFFU),\
                             (INT32U)((*ps8IpStr >> 8)&0xFFU),\
                             (INT32U)((*ps8IpStr >> 16)&0xFFU),\
                             (INT32U)((*ps8IpStr >> 24)&0xFFU));
            retCode = Ping_NonMatching_ECHOREPLY;
        }
    
        /* Print out data on correct reply */
        SoAd_vmLogActivity7(&objstrSoAdModuleInfoType, "Reply from %d.%d.%d.%d, with %d bytes, Seq=%u, TTL = %d", \
                            (INT32U)(*ps8IpStr & 0xFFU),\
                            (INT32U)((*ps8IpStr >> 8)&0xFFU),\
                            (INT32U)((*ps8IpStr >> 16)&0xFFU),\
                            (INT32U)((*ps8IpStr >> 24)&0xFFU),\
                            ICMPLen-8,\
                            Seq,\
                            ((IPHDR *)ps8Buf)->Ttl);
    
        /* Validate the data payload */
        if( ICMPLen != PING_DATALEN )
        {
            SoAd_vmLogError2(&objstrSoAdModuleInfoType, "Data length error in reply (%d of %d)", s32NumberOfBytes, PING_DATALEN);
            retCode = Ping_DataLenError_ECHOREPLY;
        }
    
    
        if( *(UINT8 *)((ps8Buf+( (((IPHDR *)ps8Buf)->VerLen & 0xF) * 4 )+8)) != (UINT8)('0'+8) )
        {
            SoAd_vmLogError3(&objstrSoAdModuleInfoType, "Data verification error in reply (%d 0x%x 0x%x)", \
                             s32NumberOfBytes, \
                             *(UINT8 *)((ps8Buf+( (((IPHDR *)ps8Buf)->VerLen & 0xF) * 4 )+s32NumberOfBytes)), \
                             '0'+s32NumberOfBytes );
            retCode = Ping_DataVerFailed_ECHOREPLY;
        }
        return retCode;
    }
    
    static void SoAd_BuildPing( INT8S *ps8Buf, INT16U u16seq )
    {
        *(ps8Buf+8) = '0'+8;
        /* Get pointers to the ICMP and ICMPREQ headers */
    
        /* Fill out echo request */
        ((ICMPHDR *)ps8Buf)->Type   = ICMP_ECHO;
        ((ICMPHDR *)ps8Buf)->Code   = 0;
        ((ICMPREQHDR *)(((ICMPHDR *)ps8Buf)->Data))->Id    = HNC16(PING_IDENTIFICATION);
        ((ICMPREQHDR *)(((ICMPHDR *)ps8Buf)->Data))->Seq   = HNC16(u16seq);
    
        /* Checksum the ICMP header */
        /* Although the checksum function is reentrant, we follow the rules */
        /* and call llEnter()/llExit() since this is a stack function. */
        llEnter();
        ICMPChecksum( (ICMPHDR *)ps8Buf, PING_DATALEN );
        llExit();
    }