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.

TM4C129ENCPDT: Sending Raw Ethernet Frames using the LwIP port

Part Number: TM4C129ENCPDT


Hi

Has anyone had any experience in sending raw ethernet frames using LwIP (1.4.1) on the TM4C129E?

I'm fine using LwIP for UDP and TCP connections, but have a specific requirement to send raw ethernet so as to communicate with a test rig and I'm struggling to find any description of the steps I need to take to achieve this. From what I can gather I need to use ethernetif.c which as far as I can work out is contained in tiva-tm4c129.c

I've followed the flow for setting up a TCP connection lwIPInit() which in turn calls lwIPPrivateInit(). From here I'm a bit uncertain as to whether lwip_init() needs to be called? I have assumed it doesnt and am just calling:

netif_add(&g_sNetIF, &ip_addr, &net_mask, &gw_addr, NULL, tivaif_init, ethernet_input);

netif_set_default(&g_sNetIF);

netif_set_up(&g_sNetIF);

before exiting back to lwIPInit() which then returns to my application. But now I'm stuck as to how I populate the 802.3 Ethernet packet and stick the data onto the wire. Any help would be greatfully appreciated.

Many thanks

  • Hi Hairy,

      Reading the code in lwiplib.c, lwIPPrivateInit() will call lwip_init() to setup the stack. Without the lwip_init(), no stack is setup, not just the tcp/udp stack which you don't intend to use but also memory, pbuf, netif, ARP and timers which are critical for the operations of Ethernet as far as I know. 

    void
    lwip_init(void)
    {
      /* Modules initialization */
      stats_init();
    #if !NO_SYS
      sys_init();
    #endif /* !NO_SYS */
      mem_init();
      memp_init();
      pbuf_init();
      netif_init();
    #if LWIP_SOCKET
      lwip_socket_init();
    #endif /* LWIP_SOCKET */
      ip_init();
    #if LWIP_ARP
      etharp_init();
    #endif /* LWIP_ARP */
    #if LWIP_RAW
      raw_init();
    #endif /* LWIP_RAW */
    #if LWIP_UDP
      udp_init();
    #endif /* LWIP_UDP */
    #if LWIP_TCP
      tcp_init();
    #endif /* LWIP_TCP */
    #if LWIP_SNMP
      snmp_init();
    #endif /* LWIP_SNMP */
    #if LWIP_AUTOIP
      autoip_init();
    #endif /* LWIP_AUTOIP */
    #if LWIP_IGMP
      igmp_init();
    #endif /* LWIP_IGMP */
    #if LWIP_DNS
      dns_init();
    #endif /* LWIP_DNS */
    
    #if LWIP_TIMERS
      sys_timeouts_init();
    #endif /* LWIP_TIMERS */

    I have not done any Ethernet communication without using the TCP/IP stack. Therefore, I'm sorry I may not be able to provide good guidance. I think if you reach out to LwIP forum, the experts there may be able to provide some hints. In any case, during holiday, the response from LwIP or here will be much delayed. I will be out of office until next year. 

    Although this may not be the solution you are looking for, one thing I can suggest is to look at how the Ethernet bootloader send the raw packets to the server. See below the snippet of code in bl_emac.c file. The SendBOOTPRequest() constructs a BootP packet and use the uip_udp_send to send the raw packet. Note that this is not using LwIP but rather uIP for rudimentary Ethernet packet transfers. Not sure if this the right solution for you. Again, please do reach out to LwIP forum for their feedback. I apologize for lack for guidance and I will be out of office starting today. 

    //*****************************************************************************
    //
    //! Constructs and sends a BOOTP request packet.
    //!
    //! This function constructs a BOOTP request packet and sends it as a broadcast
    //! message to the network.
    //!
    //! \return None.
    //
    //*****************************************************************************
    static void
    SendBOOTPRequest(void)
    {
        uint8_t *pui8Packet = (uint8_t *)uip_appdata;
        tBOOTPPacket *psBOOTP = (tBOOTPPacket *)uip_appdata;
        uint32_t ui32Idx;
    
        //
        // Zero fill the BOOTP request packet.
        //
        for(ui32Idx = 0; ui32Idx < sizeof(tBOOTPPacket); ui32Idx++)
        {
            pui8Packet[ui32Idx] = 0;
        }
    
        //
        // Construct a BOOTP request.
        //
        psBOOTP->ui8Op = BOOTP_REQUEST;
    
        //
        // Set the hardware type to Ethernet.
        //
        psBOOTP->ui8HType = 0x01;
    
        //
        // Set the hardware address length to 6.
        //
        psBOOTP->ui8HLen = 0x06;
    
        //
        // Choose a random number for the transaction ID.
        //
        psBOOTP->ui32XID = g_ui32XID = RandomNumber();
    
        //
        // Set the number of seconds since we started.
        //
        psBOOTP->ui16Secs = HTONS(g_ui32Ticks / SYSTICKHZ);
    
        //
        // Fill in the Ethernet MAC address.
        //
        for(ui32Idx = 0; ui32Idx < 6; ui32Idx++)
        {
            psBOOTP->pui8CHAddr[ui32Idx] = g_sMACAddr.addr[ui32Idx];
        }
    
        //
        // Set the server name if defined.
        //
    #ifdef ENET_BOOTP_SERVER
        for(ui32Idx = 0;
            (psBOOTP->pcSName[ui32Idx] = ENET_BOOTP_SERVER[ui32Idx]) != 0;
            ui32Idx++)
        {
        }
    #endif
    
        //
        // Send the BOOTP request packet.
        //
        uip_udp_send(sizeof(tBOOTPPacket));
    }

  • Hi Charles,

    Thanks for the pointer to the bl_emac.c file. I'll have a dig into it and report back.

    HL

  • Looks like I was over thinking it. Turns out that calling lwIPInit, allocating a pbuf to which the frame you want send is assigned and then sending the frame directly using the linkoutput function is all thats required

  • Hi Hairy,

      Really glad that you figure out how to do it. Will you be so kind to show some code snippet that may benefit others in the community including me. :-)

  • Hi Charles,

    The enet_lwip example can be used to init LwIP, once complete than a raw frame can be placed onto the wire using the following function:

    void 
    SendRawEnet(void)
    {
        uint8_t data[0x4D] =
        {    
            0xff,0xff,0xff,0xff,0xff,0xff,
            0x08,0x00,0x28,0x5A,0x91,0x92,
            0x88,0xb5,
            0xcb,0xda,0xe9,0xf8,
            0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
            0x03,
            0x00,0x00,0x00,
            0x27,0x2d,0x10,0x35,0xc8,0xff,0x09,0x89,0xdd,0x00,0x8a,0x13,0x42,0x40,0xf5,0x0b,
            0x00,0x00,0xe8,0x0b,0x00,0x00,0x21,0x00,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x20,
            0x00,0x00,0x00,0x00,0x93,0x00,0x00
        };
            
        struct pbuf *p_pbuf;
        
        /**  Assign buffer space. */
        p_pbuf = pbuf_alloc(PBUF_TRANSPORT, 0x4D, PBUF_POOL);
        
        if (NULL != p_pbuf)
        {
            /**  Add the frame to the buffer. Copy application supplied data into a pbuf */
            pbuf_take(p_pbuf, data, 0x4D);
    
            /** Send the data directly to the link medium. */
            g_sNetIF.linkoutput(&g_sNetIF, p_pbuf);
    
            pbuf_free(p_pbuf);
        }
    }

  • Hi Hairy,

      Thank you!