lwip-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [lwip-users] Incoming packet bigger than PBUF_POOL_BUFSIZE


From: Gary Spivey
Subject: Re: [lwip-users] Incoming packet bigger than PBUF_POOL_BUFSIZE
Date: Thu, 8 Dec 2011 23:45:40 +0000

I set the following in my lwipopts.h
#define TCP_MSS                         1536
#define TCP_SND_BUF                     1536
#define PBUF_LINK_HLEN                  16
//#define ETH_PAD_SIZE                    2

This runs through DHCP.

When I change it to this:
#define TCP_MSS                         1536
#define TCP_SND_BUF                     1536
//#define PBUF_LINK_HLEN                  16
#define ETH_PAD_SIZE                    2

The netif_is_up call in my ethernetif_init never returns positive. 

I think the files of interest on my end are the ethernetif.h and .c, and the 
arch/cc.h file. I am using the CrossWorks compiler, so my arch/cc.h file looks 
like this:
#ifndef __CC_H__
#define __CC_H__
#include <types.h>
#include <string.h>

#define BYTE_ORDER LITTLE_ENDIAN 
/* Compiler hints for packing structures */
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT __attribute__ ((packed))
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
/* prototypes for printf() and abort() */
#include <stdio.h>
#include <stdlib.h>
/* Plaform specific diagnostic output */
#ifndef LWIP_PLATFORM_ASSERT
#define LWIP_PLATFORM_ASSERT(x) while(1);
#endif
#endif /* __CC_H__ */

My ethernetif.h file basically contains prototypes and the following:
typedef struct netif ethernetif_t;

My ethernetif.c file is attached below ...

I will work more with a hub and wireshark to see if I can pin down the DHCP 
problem further. But any info you can shed on my setup or what should be 
happening is most appreciated.

#include <data_types.h>
#include <board.h>
#include <emac.h>
#include <sys_time.h>
#include <ethernetif.h>
#include <lwipopts.h>
#include "lwip/mem.h"
#include "lwip/init.h"
#include "lwip/netif.h"
#include "lwip/dhcp.h"
#include "lwip/pbuf.h"
#include "lwip/tcp.h"
#include "lwip/tcp_impl.h"
#include "lwip/dns.h"
#include "lwip/stats.h"
#include "lwip/ip_frag.h"
#include "lwip/ip_addr.h"
#include "netif/etharp.h"


//-----------------------------------------------------------------------------
//      __   __        __  ___           ___  __
//     /  ` /  \ |\ | /__`  |   /\  |\ |  |  /__`
//     \__, \__/ | \| .__/  |  /~~\ | \|  |  .__/
//
//-----------------------------------------------------------------------------

//Define the interface name
#define IFNAME0 'e'
#define IFNAME1 'n'

//-----------------------------------------------------------------------------
//     ___      __   ___  __   ___  ___  __
//      |  \ / |__) |__  |  \ |__  |__  /__`
//      |   |  |    |___ |__/ |___ |    .__/
//
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
//                __          __        ___  __
//     \  /  /\  |__) |  /\  |__) |    |__  /__`
//      \/  /~~\ |  \ | /~~\ |__) |___ |___ .__/
//
//-----------------------------------------------------------------------------

static ethernetif_t ethernetif_allocator;
static ip_addr_t ipaddr;
static ip_addr_t netmask;
static ip_addr_t gw;
static uint32_t  lwip250mStimer;

//-----------------------------------------------------------------------------
//      __   __   __  ___  __  ___      __   ___  __
//     |__) |__) /  \  |  /  \  |  \ / |__) |__  /__`
//     |    |  \ \__/  |  \__/  |   |  |    |___ .__/
//
//-----------------------------------------------------------------------------

static err_t ethernetif_hardware_init(ethernetif_t * ethernetif);
static err_t ethernetif_send(ethernetif_t *ethernetif, struct pbuf *p);
static void  ethernetif_receive(ethernetif_t * ethernetif);
static void ethernetif_process_timers(void);

//-----------------------------------------------------------------------------
//      __        __          __
//     |__) |  | |__) |    | /  `
//     |    \__/ |__) |___ | \__,
//
//-----------------------------------------------------------------------------

//==============================================================================
// I don't know where to put this - lwip doesn't define this function. 
// But it is the same as my sys_time.
//==============================================================================
u32_t sys_now(void) 
{
  return(sys_time());
}

//==============================================================================
ethernetif_t * ethernetif_get_handle()
{
  return(&ethernetif_allocator);
}

//==============================================================================
// This should be called by the board.c file when it is setting up the
// hardware.
//==============================================================================
void ethernetif_init(ethernetif_t * ethernetif)
{
  uint32_t last_time;

  // Set up the LWIP functions
  
  // startup defaults (may be overridden by one or more opts)
  IP4_ADDR(&ipaddr,  192,168,1,2);
  IP4_ADDR(&gw,      192,168,1,1);
  IP4_ADDR(&netmask, 255,255,255,0);

  // Initialize the lwip functions
  lwip_init();

  // Add the network interface
  netif_add(ethernetif, &ipaddr, &netmask, &gw, NULL, ethernetif_hardware_init, 
ethernet_input);

  // Set it as the default
  netif_set_default(ethernetif);

  // Set up the interface
  //netif_set_up(ethernetif);

  // Start dhcp
  dhcp_start(ethernetif);
  last_time = sys_time();
  while (!netif_is_up(ethernetif))
  {
    if (sys_time() > last_time + 250)
    {
      ethernetif_process_timers();
      last_time = sys_time();
    }
    ethernetif_receive(ethernetif);
  }
}


//==============================================================================
void ethernetif_process(ethernetif_t * ethernetif)
{
  uint32_t timestamp;
  uint8_t  first_time = 1;

  // See if we rolled over - if so, adjust the timestamp to match
  // Also check if this is our first time. If so, set up the timestamp.
  if ((first_time) || (sys_time() < timestamp))
  {
    timestamp = sys_time();
    first_time = 0;
  }

  // We will do the ethernetif processing here. Initially, we can just poll.
  // Later, I can use a flag via interrupt - although, polling will likely
  // be the same as checking the flag. Maybe not.
  ethernetif_receive(ethernetif);

  // Check on the ethernet timers every 250 ms
  if (sys_time() > timestamp + 250)
  {
    // If we have gone 250ms, process the timers
    ethernetif_process_timers();
    timestamp = sys_time();
  }
}

//-----------------------------------------------------------------------------
//      __                  __        __        __
//     /  `  /\  |    |    |__)  /\  /  ` |__/ /__`
//     \__, /~~\ |___ |___ |__) /~~\ \__, |  \ .__/
//
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
//      __   __              ___  ___
//     |__) |__) | \  /  /\   |  |__
//     |    |  \ |  \/  /~~\  |  |___
//
//-----------------------------------------------------------------------------

//=============================================================================
//  Run this every 250mS to update lwIP timers
//=============================================================================
static void ethernetif_process_timers(void)
{
    lwip250mStimer += 250;
    if( (lwip250mStimer % TCP_TMR_INTERVAL) == 0 ) { tcp_tmr(); }
    if( (lwip250mStimer % ARP_TMR_INTERVAL) == 0 ) { etharp_tmr(); }
#if IP_REASSEMBLY
    if( (lwip250mStimer % IP_TMR_INTERVAL) == 0 ) { ip_reass_tmr(); }
#endif
#if LWIP_AUTOIP
    if( (lwip250mStimer % AUTOIP_TMR_INTERVAL ) == 0 ) { autoip_tmr(); }
#endif
#if LWIP_IGMP
    if( (lwip250mStimer % IGMP_TMR_INTERVAL ) == 0 ) { igmp_tmr(); } 
#endif
#if LWIP_DHCP
    if( (lwip250mStimer % DHCP_FINE_TIMER_MSECS ) == 0 ) { dhcp_fine_tmr(); }
    if( (lwip250mStimer % (DHCP_COARSE_TIMER_SECS*1000) ) == 0 ) { 
dhcp_coarse_tmr(); }
#endif
#if LWIP_DNS
    if( (lwip250mStimer % DNS_TMR_INTERVAL) == 0 ) { dns_tmr(); }
#endif
}

//==============================================================================
static err_t ethernetif_send(ethernetif_t *ethernetif, struct pbuf *p)
{
  err_t retval = ERR_OK;
  // Send the packet - we don't need the ethernetif info as we just have the one
  // interface. Also, we don't need to check the total bytes as this is just
  // double-checking the lwip structs.
  while ( (NULL != p) && (ERR_OK == retval) )
  {
    if (SUCCESS(emac_send(p->payload, p->len)))
    {
      retval = ERR_OK;
    }
    else
    {
      retval = ! ERR_OK;
    }
    p = p->next;
  }
  return retval;
}

//==============================================================================
// This function should be called when a packet is ready to be read
// from the interface (either because we are polling, or because an interrupt
// has told us it is time to read).
// Should allocate a pbuf and transfer the bytes of the incoming
// packet from the interface into the pbuf if something exists.
// 
// @param ethernetif the lwip network interface structure for this ethernetif
//==============================================================================
static void ethernetif_receive(ethernetif_t * ethernetif)
{
  struct eth_hdr *ethhdr;
  struct pbuf *p, *chainp;
  uint32_t bufsize;
  uint32_t bytes_read;
  uint32_t bytes_to_read;

  // See if there is a packet to get
  if (FALSE(emac_checkReceiveIndex()))
  {
    p = NULL;
  }
  else
  {
    // See how much data we need to allocate
    bufsize = emac_getReceiveDataSize();
    // If there is data (and there should be ...)
    if (bufsize) 
    {
      // Allocate a chain of pbufs big enough to hold it
      p = pbuf_alloc(PBUF_RAW,  bufsize, PBUF_POOL);
      // Set up our linked-list index
      chainp = p;
      // Now let's copy the data into our chain
      while (bufsize)
      {
        // Don't read more than one buffer at a time
        bytes_to_read = MINIMUM(bufsize, PBUF_POOL_BUFSIZE);
        bytes_read = emac_receive(chainp->payload, bytes_to_read);
        // If something goes wrong, we will bail
        // I don't know what this will mean to the rest of the system
        if ( bytes_read == 0) 
        {
          pbuf_free(p);
          p = NULL;
          bufsize = 0;
        }
        // If we successfully read, advance the chain and decrement the amount
        // of data left to read.
        else
        {
          chainp = chainp->next;
          bufsize -= bytes_read;
        }
      }
    }
  }

  // If we have a packet, 
  if (p != NULL) {
    // points to packet payload, which starts with an Ethernet header
    ethhdr = (struct eth_hdr *) p->payload;
    switch (htons(ethhdr->type)) {
    // IP or ARP packet? 
    case ETHTYPE_IP:
    case ETHTYPE_ARP:
#if PPPOE_SUPPORT
    // PPPoE packet? 
    case ETHTYPE_PPPOEDISC:
    case ETHTYPE_PPPOE:
#endif // PPPOE_SUPPORT
      // send complete packet to tcpip_thread to process
      if (ethernetif->input(p, ethernetif)!=ERR_OK)
      { 
        // If there was a problem with the packet, free it up
        pbuf_free(p);
      }
      break;
    default:
      pbuf_free(p);
      break;
    }
  }
}

//==============================================================================
// Should be called at the beginning of the program to set up the
// network interface. It calls the function low_level_init() to do the
// actual setup of the hardware.
// 
// This function should be passed as a parameter to netif_add().
// 
// @param ethernetif the lwip network interface structure for this ethernetif
// @return ERR_OK if the loopif is initialized
//         ERR_MEM if private data couldn't be allocated
//         any other err_t on error
//==============================================================================
static err_t ethernetif_hardware_init(ethernetif_t * ethernetif)
{
  struct pbuf *p;
  err_t retval;
  emac_t * emac;
  uint8_t i;

  // Initialize the low-level hardware
  emac = emac_get_handle();
  emac->Mode = EMAC_MODE_AUTO;

  if (SUCCESS(emac_init(emac)))
  {
    retval = ERR_OK;
  }
  else
  {
    retval = !ERR_OK;
  }

  //
  // Set up the lwip network interface
  //
#if LWIP_NETIF_HOSTNAME
  // Initialize interface hostname 
  ethernetif->hostname = "C3PO";
#endif 

  // Initialize the snmp variables and counters inside the ethernetif_t 
  // The last argument should be replaced with your link speed, in units
  // of bits per second.
  //NETIF_INIT_SNMP(ethernetif, snmp_ifType_ethernet_csmacd, 
LINK_SPEED_OF_YOUR_NETIF_IN_BPS);
  // I am totally guessing about the link speed here.
  //NETIF_INIT_SNMP(ethernetif, snmp_ifType_ethernet_csmacd, 10000000);

  ethernetif->name[0] = IFNAME0;
  ethernetif->name[1] = IFNAME1;

  // We directly use etharp_output() here to save a function call.
  // You can instead declare your own function an call etharp_output()
  // from it if you have to do some checks before sending (e.g. if link
  // is available...)
  ethernetif->output = etharp_output;
  //ethernetif->linkoutput = (ethernetif_linkoutput_fn) ethernetif_send;
  ethernetif->linkoutput = ethernetif_send;
  
  // set MAC hardware address length
  ethernetif->hwaddr_len = ETHARP_HWADDR_LEN;
  // Set MAC address. It is required that the emac_address be set in the emac
  // handle for the lower-level driver. We will just copy that address up
  // into our ethernetif.
  for (i = 0; i < 6; i++)
  {
    ethernetif->hwaddr[i] = emac->emac_address[i];
  }

  // maximum transfer unit - I don't see why this shouldn't be as big as the
  // ethernet can handle. Our lwip interface should be able to handle this.
  ethernetif->mtu = EMAC_MAX_FRAME_LENGTH;
  //ethernetif->mtu = MINIMUM(EMAC_MAX_FRAME_LENGTH, PBUF_POOL_BUFSIZE-4);
  
  // device capabilities 
  // don't set NETIF_FLAG_ETHARP if this device is not an ethernet one 
  ethernetif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | 
NETIF_FLAG_LINK_UP;

  return retval;
}


-----Original Message-----
From: address@hidden [mailto:address@hidden On Behalf Of Kieran Mansley
Sent: Thursday, December 08, 2011 12:25 PM
To: Mailing list for lwIP users
Subject: Re: [lwip-users] Incoming packet bigger than PBUF_POOL_BUFSIZE


On 8 Dec 2011, at 18:51, Gary Spivey wrote:

> What is the preferred way to configure lwip so that I can either accept 
> packets larger than PBUF_POOL_BUFSIZE or ensure that I don't receive them?

To accept packets larger than PBUF_POOL_BUFSIZE you should, when you receive 
them, copy them into the chain of pbufs that you get when you alloc, being 
careful to split the received data across the pbufs as necessary.

To ensure that you don't receive packets larger than PBUF_POOL_BUFSIZE, set 
that value larger than the biggest packet you can receive.  This is a property 
of the LAN you are connected to (i.e. it is a value that should be known by all 
the hosts and configured the same) and can vary, so I can't tell you a good 
value.  

In the default, we assume that the largest value on the network is 
MSS+40+PBUF_LINK_HLEN, where the 40 is for IP and TCP headers.  It is possible 
for TCP headers to be bigger than that (if there are options included for 
example) or for another host on the network to have a larger MSS and MTU than 
lwIP's default, and so you may need to adjust PBUF_POOL_BUFSIZE to match if you 
want to fit a frame into a single buffer.

I'm not sure whey DHCP didn't work when you started splitting packets across 
buffers.  It should.  It's either a bug in lwIP or a bug in the way you were 
filling the buffers.  If you can get more information on the reason for the 
failure that would be useful.

Note that you should also handle chains of pbufs on the send path in your 
driver.  With a relatively small PBUF_POOL_BUFSIZE lwIP can pass packets for 
transmission to the driver as a chain as well.

Hope that helps,

Kieran
_______________________________________________
lwip-users mailing list
address@hidden
https://lists.nongnu.org/mailman/listinfo/lwip-users





reply via email to

[Prev in Thread] Current Thread [Next in Thread]