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.

fdSelect function not returning with broadcast UDP packets on Port 23

Other Parts Discussed in Thread: TM4C1294KCPDT, SYSBIOS

Processor is a TM4C1294KCPDT TIVA on a proprietary PCBA.  Using NDK version 2.24.03.35 and TI-RTOS version 2.14.0.10.  The TIVA board is on a 10/100 ethernet LAN using DHCP.  A PC is also on the network.  The network is physically isolated with the only other device on the network being a router.

Our proprietary PC application sends out a broadcast packet  (Destination IP=255.255.255.255, Destination MAC=FF:FF:FF:FF:FF:FF); Source Port is 23, Destination Port is 23.  The packet has four bytes of data (total packet length is 46 bytes.  I have confirmed this using WIRESHARK.)  Unfortunately, the TIVA does not seem to receive this packet.  By this I mean that the fdSelect in the code below does not return.  The TIVA board will, however, still respond to a ping to the IP address it received from the DHCP server.

I have tried this with the NDK priority in my app.cfg file set to both high and low priority via XCONF.

Here are the priorities for the various tasks running:

// TASK Priorities
#define HandpadAction_Task_Priority        0x01
#define Housekeeping_Task_Priority        0x02
#define I2C_Eeprom_Task_Priority        0x03
//        NDK Low Task Priority            0x04   (changed to this value via XCONF)
#define RS485Scan_Task_Priority            0x05
#define TrajectGen_Task_Priority        0x06
#define Parser_Task_Priority            0x07
//        NDK Normal Task Priority        0x09 (changed to this value via XCONF)
#define Netbios_Task_Priority            0x0B
#define USBResponse_Task_Priority        0x0B
#define Socket_Task_Priority            0x0B
#define TelnetResponse_Task_Priority    0x0B
#define HTTPResponse_Task_Priority        0x0B
#define RS485Response_Task_Priority        0x0B
//        NDK High Task Priority            0x0D (changed to this value via XCONF)
//        NDK Kernal Task Priority        0x0F   (changed to this value via XCONF)

The following function is called after the TIVA has received an IP address:


//*****************************************************************************
//
// Routine to spawn the UDP Discovery Request Handler Task.
//  This is called after an IP address has been received from the network
//  DHCP server
//
//*****************************************************************************
void SpawnNetbiosTask(void)
{
    Error_Block eb;

    // Initialize error reporting object
    Error_init(&eb);

    // Initialize Netbios Task Parameters
    // (Hint: arg0 will be the port that this task listens to)
    Task_Params_init(&Netbios_Task_Params);
    Netbios_Task_Params.stackSize = Netbios_Task_Stack_Size;
    Netbios_Task_Params.priority = Netbios_Task_Priority;
    Netbios_Task_Params.arg0 = UDPPORT;

    // Launch the Netbios Task
    Netbios_Task_Handle = Task_create((Task_FuncPtr)Netbios_Task_Handler, &Netbios_Task_Params, &eb);
    if (Netbios_Task_Handle == NULL) {
        System_printf("Task_create(Netbios Task Create) failed!\n");
        System_flush();
        BIOS_exit(0);
    }

}// End: void SpawnNetbiosTask(void)

This is the task handler.  I have confirmed that it runs to the fdSelect function, enters that function, but never returns:
//======================================================================================
//======================================================================================
//
//        =========     NETBIOS TASK HANDLER    ==========
//
//======================================================================================
//======================================================================================
void Netbios_Task_Handler(void)
{

    int                 i_bytesRcvd, i_bytesSent, i_status, i_addrlen, i_error;
    SOCKET                 s_UdpSocket;
    fd_set                s_readSet;
    struct sockaddr_in    s_localAddr, s_clientAddr;

    char                pc_rx_buffer[UDPPACKETSIZE], pc_tx_buffer[UDPPACKETSIZE];
    char                 ps_netbios_name[NETBIOS_NAME_LEN+1];
    NETBIOS_HDR*          ps_netbios_hdr;
    NETBIOS_NAME_HDR*   ps_netbios_name_hdr;
    NETBIOS_RESP*          ps_resp;

    System_printf("Beginning NetbiosTask\n");
    System_flush();

    // Create socket to listen for PC's discovery UDP broadcast packets
    fdOpenSession(TaskSelf());
    s_UdpSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (INVALID_SOCKET == s_UdpSocket)
    {
        i_error = fdError();
        switch( i_error )
        {..... error reporting code ....}

}

    // Specify what addresses to listen for....
    memset(&s_localAddr, 0, sizeof(s_localAddr));
    s_localAddr.sin_family        = AF_INET;
    s_localAddr.sin_port         = UDPPORT;     <<<======= This is defined as 23 elsewhere
    s_localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    i_status = bind(s_UdpSocket, (struct sockaddr *)&s_localAddr, sizeof(s_localAddr));
    if (-1 == i_status)
    {
        i_error = fdError();
        switch( i_error )
        {..... error reporting code ....}
    }


    // Loop looking for discovery broadcast UDP packets from the PC application
    do
    {
        // readSet and addrlen are value-result arguments, which must be reset
        // in between each select() and recvfrom() call
        FD_ZERO(&s_readSet);
        FD_SET(s_UdpSocket, &s_readSet);
        i_addrlen = sizeof(s_clientAddr);

        // Wait forever for the reply -- fdSelect(nfds, readfds, writefds, exceptfds, timeout)
        i_status = fdSelect(1, &s_readSet, NULL, NULL, NULL);    <<<==== This function never returns even when broadcast UDP packets are sent
        if (-1 == i_status) // Error
        i_error = fdError();

        switch( i_error )
        {..... error reporting code ....}

Suggestions on how to proceed?

Tom Farmer

  • Hi Tom,
    Moved this thread over TI-RTOS forum for faster and appropriate response. Thank you for you patience.
  • Tom,

    How is UDPPORT defined?  Is it in a shared #define?

    It is indicated as an argument for the  task handler:

        Task_Params_init(&Netbios_Task_Params);
        Netbios_Task_Params.stackSize = Netbios_Task_Stack_Size;
        Netbios_Task_Params.priority = Netbios_Task_Priority;
        Netbios_Task_Params.arg0 = UDPPORT;

    But the handler does not use that argument:

        void Netbios_Task_Handler(void)

    But it uses “UDPPORT” directly instead, indicated as "defined as 23 elsewhere":

        s_localAddr.sin_port         = UDPPORT;     <<<======= This is defined as 23 elsewhere
        s_localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
        i_status = bind(s_UdpSocket, (struct sockaddr *)&s_localAddr, sizeof(s_localAddr));

    Are you sure that UDPPORT is the same (23)  in all cases?  I expect the answer is yes, but just checking.

    Also, have you tried checking stack and memory usage in ROV?

    Thanks,
    Scott

  • UDPPORT is defined as 23.

    Per ROV, none of the tasks running exceed 75% of their available stack size.  Most are less than half.

    It looks like the task handler above is blocked, waiting at Semaphore.c line 262.

  • Tom,

    It may be that the broadcast packets are being filtered away, either by the Ethernet driver or the upper layers of the stack.  

    There is one function NIMUReceivePacket() where all received packets are routed through.  If the broadcast packets make it there, it will rule out filtering by the driver.

    A quick way to check filtering by the driver is to look at the global IP stats structure “ips”:
    1) Halt the target
    2) Check the IP stats value “ips.Delivered”
    3) Let the target run, and immediately send the broadcast
    4) Halt the target and check if ips.Delivered incremented.  If it did not, then this points to filtering of the broadcast by the driver.  If it did increment, it may be due to other incoming packets (if there was other simultaneous traffic).  In that case, you may need to use breakpoints or instrument NIMUReceivePacket() to check if the broadcast packet arrives there or not.

    Another thing to do is to add a temporary print statement in your application’s .cfg file to check your configuration.  Add this, and see what gets displayed as you rebuild the app:

    Ip = xdc.useModule(“ti.ndk.config.Ip”);
    print(“IP bcast value: “ + Ip.enableDirectedBroadcast);

    Finally, port 23 is usually reserved for Telnet.  Have you tried different port numbers?

    Regards,
    Scott

  • Hi Scott,

    Background:  We have an existing Stellaris-based product that I am trying to port to TIVA.  It communicates with a proprietary windows application that uses a proprietary driver.  I am unable to modify the PC driver / application.  I trying to get the existing application to talk to the new TIVA board. 

    The application discovery process is:

    1.  PC sends a Port 23 broadcast UDP packet  from its PORT 23 that contains a "magic data" 4-byte sequence.  This is sent to IP address 255.255.255.255 with MAC Address ff:ff:ff:ff:ff:ff.

    2.  Upon hearing the broadcast UDP packet, the device sends back a UDP PORT 23 packet with more "magic data".

    3.  PC sends a TCP packet from its Port 55900 to device Port 23.

    4.  Device sends a TCP packet from its Port 23 to PC Port 55900.

    5.  PC sends a TCP packet from its Port 55900 to device Port 23

    6.  Device sends a TELNET packet from its Port 23 to PC Port 55900.

    7.  From then on, all comms are TELNET packets.

    I am currently trying to get the device to see #1 and pass it up into my code for checking.  My code never receives the broadcast packet.

    So, to answer your specific questions:

    1.  ips.Delivered -- This counter seems to be incrementing once with each broadcast packet from the PC.  As far as digging into the NIMUReceivePacker function, I will need more instructions on how to access that code and install source-code breakpoints.

    2.  IpDirectedBCast -- The print statement you suggested for the .cfg file results in an illegal character message at file save.  Without the statement, the build proceeds fine.  I did put a watch on _ipcfg.IpDirectedBCast.  This is set to 1 at load time and never changes.  Using XCONF, I also looked at the IP settings; Enable directed broadcast is checked.

    3.  Port 23 -- I cannot change this since I do not have access to the PC application

    What do you suggest for a next step?

    Tom

  • Tom,

    Thanks for the additional details.  If the packet is arriving from the driver it seems it is being filtered in the upper layers of the stack for some reason.  
    It is unfortunate you can’t try a different port number, in case port 23 is treated special for some reason.

    I will have to talk to the NDK team about this and get some more suggestions.  I will get back to you when I have some ideas…

    Regards,
    Scott

  • Tom,

    Tom Farmer said:
    Background:  We have an existing Stellaris-based product that I am trying to port to TIVA.  It communicates with a proprietary windows application that uses a proprietary driver.  I am unable to modify the PC driver / application.  I trying to get the existing application to talk to the new TIVA board.

    Was the Stellaris app also using the NDK and TI-RTOS?


    Steve

  • Hi Steve,

    No.  The Stellaris app used an older version of SYSBIOS (more than 4 years old from today).  The network functionality was implemented using lwip.  To make it work the previous engineer made some significant changes to both that were not documented.  The discovery protocol described above was in the modified version of the lwip NETBIOS.c module.

    Tom

  • Ok.  I was hoping it was an NDK app on Stellaris, too.

    Is Telnet server enabled in your application?  You would see some printout when the app first runs about telnet, similar to the printout telling you that the DHCP Client service is enabled, for example.  If you are not using the NDK's Telnet server, which defaults to port 23, then using port 23 for your own purpose should not be an issue.  If you are, you could configure the Telnet server to use a different port or stop using it if not needed.

    I think at this point you are going to have to debug the stack a little to see if/why your packet is being dropped.

    As Scott mentioned, all packets from the driver will come through the function NIMUReceivePacket().  This function is found in your NDK install in the file "<ndk install dir>/packages/ti/ndk/stack/nimu/nimu.c".

    Within that function, you will see a switch statement.  The "type" field of the Ethernet Frame header will be checked in this switch statement, which describes the type of data that's contained in the frame's payload.  In your case, it's an IP packet, and so it should be hitting at the IP case, or type == 0x800:

    int NIMUReceivePacket (PBM_Handle hPkt)
    {
        ....
        /* Dispatch the Packet to the appropriate protocol layer. */
        switch( Type )
        {
            case 0x800:
            {
                /* Received packet is an IP Packet. */
                IPRxPacket( ptr_pkt );
                break;
            }
    

    Step one is you should verify that your packet is reaching this point.  You could do this a couple of different ways, but no matter which you choose, it's going to be easiest to rebuild the NDK stack for debug mode.  It's not too bad, rebuilding the stack, and you can find a link to a wiki page of instructions in the NDK's release notes.


    You can start by adding some code here to check for your packet. For example, you could check for IP destination address "255.255.255.255" and source address of the PC that's sending out the broadcast.

    You could also just use breakpoints, and then analyze the contents of each packet that makes it here.  You can try this without rebuilding the stack first, but I'll just warn you that it's a little tricky because the stack libraries that are shipped are built in release mode and optimized, so when trying to single stepping and/or adding breakpoints, you'll see the PC "jump around" and it's hard to tell where you really are in the code.  That's why I recommend rebuilding the stack in debug mode (and with optimizations disabled) even if you only want to single step, etc.  But you can certainly try this first.

    Once you verify that your packet made it this far, the next step is to see how far it goes within IPRxPacket().  There are a lot of possible places it can be dropped in that function, so you'll need to add debug trace or use breakpoints as just described.

    I would give the first step (NIMUReceivePacket) a try and verify your packet is coming in there.

    Steve

  • Hi Steve,

    I attempted to follow the rebuild instructions, but ran into a few problems.  First of all the wiki says to uncomment some lines in order to get it to build a debug configuraiton; these lines are not present in the .mak file.  Second I got an error message stating that the ti.targets.arm.elf could not be found.

    Please provide explicit instructions on how to get this build AND how to set properties etc. in CCs so I can do source-code debugging.

    In spite of this difficulty I was able to make a bit of progress using the disassembly window.  The packet is getting to    /* Handle BROADCAST/MULTICAST */ in udp.c.  (Line 274).  I'm not sure what all this code does, but I am pretty sure it is getting to Line 325 and the call to SockNotify( hSock, SOCK_NOTIFY_RCVDATA ). 

    More info -- I think it is getting to Line 325 ONLY prior to the call to fdSelect in my code.  Once this executes, a breakpoint on 325 does not trip...


    Tom

  • Tom,

    I think you should be able to debug nimu.c without having to rebuild the whole NDK stack.

    Can you please try these steps?

    1. copy nimu.c from the ndk into your application's CCS project

    2. add the following path to the app's compiler include paths:
    "${COM_TI_RTSC_TIRTOSTIVAC_INSTALL_DIR}/products/ndk_2_24_03_35/packages/ti/ndk/inc"

    3. Add the following line into your *.cfg file:
    var Pppoe = xdc.useModule('ti.ndk.config.Pppoe');

    4. Build your project. This should build the local copy of nimu.c. Make sure your app is being built in debug mode.

    5. Load the app

    6. Set a breakpoint at NIMUReceivePacket and run the app

    7. Your b/p should hit as soon as some data comes into the stack

    8. You should be able to single step through NIMUReceivePacket now.

    9. You can update the local copy of nimu.c to add the checks as described previously.

    Please let me know how it goes.

    Steve
  • Well, I have figured out where the packet is being rejected but not why -- the *SockPcbFind function in sockpcb.c. The specific reason is that the byte order for the port is getting reversed somewhere. (Hint: back in the bind statement I set the port to 23 (0x17)).

    The *SockPcbFind function is called with LPort and FPort set to 0x1700. At line 150:

    /* If local ports don't match, this entry can't match */
    if( ps->LPort != LPort )
    continue;

    ps->LPort is actually 0x17 while LPort is 0x1700. Hence the comparison fails.

    I suspect the problem is that the bind is causing the 23 (0x17) to be put into a data structure somewhere while the packet processing is using the opposite order.  Which of these paths is "wrong"? 

    I could try reversing the byte order in my bind statement, but that code would break if a future version of NDK changes one of these.

    Anyway, I decided to do an htons on the UDPPORT when it is assigned into my localaddress sockaddr_in data structure and it seemed to work. 

    Is this a viable long-term solution?

  • Tom,


    Very glad you got past your issue.  And yes -  It's standard practice to convert the port to network byte order when assigning it into the socket address structure.

    You need to have the htons() port number.

    Steve