www.pudn.com > lwip-1.3.0.rar > stellarisif.c


/** 
 * @file - stellarisif.c 
 * lwIP Ethernet interface for Stellaris Devices 
 * 
 */ 
 
/** 
 * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 
 * All rights reserved. 
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met: 
 * 
 * 1. Redistributions of source code must retain the above copyright notice, 
 *    this list of conditions and the following disclaimer. 
 * 2. Redistributions in binary form must reproduce the above copyright notice, 
 *    this list of conditions and the following disclaimer in the documentation 
 *    and/or other materials provided with the distribution. 
 * 3. The name of the author may not be used to endorse or promote products 
 *    derived from this software without specific prior written permission. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
 * OF SUCH DAMAGE. 
 * 
 * This file is part of the lwIP TCP/IP stack. 
 * 
 * Author: Adam Dunkels  
 * 
 */ 
 
/** 
 * Copyright (c) 2008 Luminary Micro, Inc. 
 * 
 * This file is dervied from the ``ethernetif.c'' skeleton Ethernet network 
 * interface driver for lwIP. 
 * 
 */ 
 
#include "lwip/opt.h" 
#include "lwip/def.h" 
#include "lwip/mem.h" 
#include "lwip/pbuf.h" 
#include "lwip/sys.h" 
#include  
#include  
#include "netif/etharp.h" 
#include "netif/ppp_oe.h" 
#include "netif/stellarisif.h" 
 
/** 
 * Sanity Check:  This interface driver will NOT work if the following defines 
 * are incorrect. 
 * 
 */ 
#if (PBUF_LINK_HLEN != 16) 
#error "PBUF_LINK_HLEN must be 16 for this interface driver!" 
#endif 
#if (ETH_PAD_SIZE != 2) 
#error "ETH_PAD_SIZE must be 2 for this interface driver!" 
#endif 
#if (!SYS_LIGHTWEIGHT_PROT) 
#error "SYS_LIGHTWEIGHT_PROT must be enabled for this interface driver!" 
#endif 
 
/** 
 * Number of pbufs supported in low-level tx/rx pbuf queue. 
 * 
 */ 
#ifndef STELLARIS_NUM_PBUF_QUEUE 
#define STELLARIS_NUM_PBUF_QUEUE    20 
#endif 
 
/** 
 * Luminary Micro DriverLib Header Files required for this interface driver. 
 * 
 */ 
#include "../../../../../hw_memmap.h" 
#include "../../../../../hw_types.h" 
#include "../../../../../hw_ints.h" 
#include "../../../../../hw_ethernet.h" 
#include "../../../../../src/ethernet.h" 
#include "../../../../../src/interrupt.h" 
#include "../../../../../src/sysctl.h" 
 
/* Define those to better describe your network interface. */ 
#define IFNAME0 'l' 
#define IFNAME1 'm' 
 
/* Helper struct to hold a queue of pbufs for transmit and receive. */ 
struct pbufq { 
  struct pbuf *pbuf[STELLARIS_NUM_PBUF_QUEUE]; 
  unsigned long qwrite; 
  unsigned long qread; 
  unsigned long overflow; 
}; 
 
/* Helper macros for accessing pbuf queues. */ 
#define PBUF_QUEUE_EMPTY(q) \ 
    (((q)->qwrite == (q)->qread) ? true : false) 
 
#define PBUF_QUEUE_FULL(q) \ 
    ((((((q)->qwrite + 1) % STELLARIS_NUM_PBUF_QUEUE)) == (q)->qread) ? \ 
    true : false ) 
 
/** 
 * Helper struct to hold private data used to operate your ethernet interface. 
 * Keeping the ethernet address of the MAC in this struct is not necessary 
 * as it is already kept in the struct netif. 
 * But this is only an example, anyway... 
 */ 
struct ethernetif { 
  struct eth_addr *ethaddr; 
  /* Add whatever per-interface state that is needed here. */ 
  struct pbufq txq; 
  struct pbufq rxq; 
}; 
 
/** 
 * Global variable for this interface's private data.  Needed to allow 
 * the interrupt handlers access to this information outside of the 
 * context of the lwIP netif. 
 * 
 */ 
static struct ethernetif ethernetif_data; 
 
/** 
 * Pop a pbuf packet from a pbuf packet queue 
 * 
 * @param q is the packet queue from which to pop the pbuf. 
 * 
 * @return pointer to pbuf packet if available, NULL otherswise. 
 */ 
static struct pbuf * 
dequeue_packet(struct pbufq *q) 
{ 
  struct pbuf *pBuf; 
  SYS_ARCH_DECL_PROTECT(lev); 
 
  /** 
   * This entire function must run within a "critical section" to preserve 
   * the integrity of the transmit pbuf queue. 
   * 
   */ 
  SYS_ARCH_PROTECT(lev); 
 
  if(PBUF_QUEUE_EMPTY(q)) { 
    /* Return a NULL pointer if the queue is empty. */ 
    pBuf = (struct pbuf *)NULL; 
  } 
  else { 
    /** 
     * The queue is not empty so return the next frame from it 
     * and adjust the read pointer accordingly. 
     * 
     */ 
    pBuf = q->pbuf[q->qread]; 
    q->qread = ((q->qread + 1) % STELLARIS_NUM_PBUF_QUEUE); 
  } 
 
  /* Return to prior interrupt state and return the pbuf pointer. */ 
  SYS_ARCH_UNPROTECT(lev); 
  return(pBuf); 
} 
 
/** 
 * Push a pbuf packet onto a pbuf packet queue 
 * 
 * @param p is the pbuf to push onto the packet queue. 
 * @param q is the packet queue. 
 * 
 * @return 1 if successful, 0 if q is full. 
 */ 
static int 
enqueue_packet(struct pbuf *p, struct pbufq *q) 
{ 
  SYS_ARCH_DECL_PROTECT(lev); 
  int ret; 
 
  /** 
   * This entire function must run within a "critical section" to preserve 
   * the integrity of the transmit pbuf queue. 
   * 
   */ 
  SYS_ARCH_PROTECT(lev); 
 
  if(!PBUF_QUEUE_FULL(q)) { 
    /** 
     * The queue isn't full so we add the new frame at the current 
     * write position and move the write pointer. 
     * 
     */ 
    q->pbuf[q->qwrite] = p; 
    q->qwrite = ((q->qwrite + 1) % STELLARIS_NUM_PBUF_QUEUE); 
    ret = 1; 
  } 
  else { 
    /** 
     * The stack is full so we are throwing away this value.  Keep track 
     * of the number of times this happens. 
     * 
     */ 
    q->overflow++; 
    ret = 0; 
  } 
 
  /* Return to prior interrupt state and return the pbuf pointer. */ 
  SYS_ARCH_UNPROTECT(lev); 
  return(ret); 
} 
 
/** 
 * In this function, the hardware should be initialized. 
 * Called from stellarisif_init(). 
 * 
 * @param netif the already initialized lwip network interface structure 
 *        for this ethernetif 
 */ 
static void 
low_level_init(struct netif *netif) 
{ 
  u32_t temp; 
  //struct ethernetif *ethernetif = netif->state; 
 
  /* set MAC hardware address length */ 
  netif->hwaddr_len = ETHARP_HWADDR_LEN; 
 
  /* set MAC hardware address */ 
  EthernetMACAddrGet(ETH_BASE, &(netif->hwaddr[0])); 
 
  /* maximum transfer unit */ 
  netif->mtu = 1500; 
 
  /* device capabilities */ 
  /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ 
  netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; 
 
  /* Do whatever else is needed to initialize interface. */ 
  /* Disable all Ethernet Interrupts. */ 
  EthernetIntDisable(ETH_BASE, (ETH_INT_PHY | ETH_INT_MDIO | ETH_INT_RXER | 
     ETH_INT_RXOF | ETH_INT_TX | ETH_INT_TXER | ETH_INT_RX)); 
  temp = EthernetIntStatus(ETH_BASE, false); 
  EthernetIntClear(ETH_BASE, temp); 
 
  /* Initialize the Ethernet Controller. */ 
  EthernetInitExpClk(ETH_BASE, SysCtlClockGet()); 
 
  /* 
   * Configure the Ethernet Controller for normal operation. 
   * - Enable TX Duplex Mode 
   * - Enable TX Padding 
   * - Enable TX CRC Generation 
   * - Enable RX Multicast Reception 
   */ 
  EthernetConfigSet(ETH_BASE, (ETH_CFG_TX_DPLXEN |ETH_CFG_TX_CRCEN | 
    ETH_CFG_TX_PADEN | ETH_CFG_RX_AMULEN)); 
 
  /* Enable the Ethernet Controller transmitter and receiver. */ 
  EthernetEnable(ETH_BASE); 
 
  /* Enable the Ethernet Interrupt handler. */ 
  IntEnable(INT_ETH); 
 
  /* Enable Ethernet TX and RX Packet Interrupts. */ 
  EthernetIntEnable(ETH_BASE, ETH_INT_RX | ETH_INT_TX); 
} 
 
/** 
 * This function should do the actual transmission of the packet. The packet is 
 * contained in the pbuf that is passed to the function. This pbuf might be 
 * chained. 
 * 
 * @param netif the lwip network interface structure for this ethernetif 
 * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) 
 * @return ERR_OK if the packet could be sent 
 *         an err_t value if the packet couldn't be sent 
 * @note This function MUST be called with interrupts disabled or with the 
 *       Stellaris Ethernet transmit fifo protected. 
 */ 
static err_t 
low_level_transmit(struct netif *netif, struct pbuf *p) 
{ 
  int iBuf; 
  unsigned char *pucBuf; 
  unsigned long *pulBuf; 
  struct pbuf *q; 
  int iGather; 
  unsigned long ulGather; 
  unsigned char *pucGather; 
 
  /** 
   * Fill in the first two bytes of the payload data (configured as padding 
   * with ETH_PAD_SIZE = 2) with the total length of the payload data 
   * (minus the Ethernet MAC layer header). 
   * 
   */ 
  *((unsigned short *)(p->payload)) = p->tot_len - 16; 
 
  /* Initialize the gather register. */ 
  iGather = 0; 
  pucGather = (unsigned char *)&ulGather; 
  ulGather = 0; 
 
  /* Copy data from the pbuf(s) into the TX Fifo. */ 
  for(q = p; q != NULL; q = q->next) { 
    /* Intialize a char pointer and index to the pbuf payload data. */ 
    pucBuf = (unsigned char *)q->payload; 
    iBuf = 0; 
 
    /** 
     * If the gather buffer has leftover data from a previous pbuf 
     * in the chain, fill it up and write it to the Tx FIFO. 
     * 
     */ 
    while((iBuf < q->len) && (iGather != 0)) { 
      /* Copy a byte from the pbuf into the gather buffer. */ 
      pucGather[iGather] = pucBuf[iBuf++]; 
 
      /* Increment the gather buffer index modulo 4. */ 
      iGather = ((iGather + 1) % 4); 
    } 
 
    /** 
     * If the gather index is 0 and the pbuf index is non-zero, 
     * we have a gather buffer to write into the Tx FIFO. 
     * 
     */ 
    if((iGather == 0) && (iBuf != 0)) { 
      HWREG(ETH_BASE + MAC_O_DATA) = ulGather; 
      ulGather = 0; 
    } 
 
    /* Initialze a long pointer into the pbuf for 32-bit access. */ 
    pulBuf = (unsigned long *)&pucBuf[iBuf]; 
 
    /** 
     * Copy words of pbuf data into the Tx FIFO, but don't go past 
     * the end of the pbuf. 
     * 
     */ 
    while((iBuf + 4) <= q->len) { 
      HWREG(ETH_BASE + MAC_O_DATA) = *pulBuf++; 
      iBuf += 4; 
    } 
 
    /** 
     * Check if leftover data in the pbuf and save it in the gather 
     * buffer for the next time. 
     * 
     */ 
    while(iBuf < q->len) { 
      /* Copy a byte from the pbuf into the gather buffer. */ 
      pucGather[iGather] = pucBuf[iBuf++]; 
 
      /* Increment the gather buffer index modulo 4. */ 
      iGather = ((iGather + 1) % 4); 
    } 
  } 
 
  /* Send any leftover data to the FIFO. */ 
  HWREG(ETH_BASE + MAC_O_DATA) = ulGather; 
 
  /* Wakeup the transmitter. */ 
  HWREG(ETH_BASE + MAC_O_TR) = MAC_TR_NEWTX; 
 
  /* Dereference the pbuf from the queue. */ 
  pbuf_free(p); 
 
  LINK_STATS_INC(link.xmit); 
 
  return(ERR_OK); 
} 
 
/** 
 * This function with either place the packet into the Stellaris transmit fifo, 
 * or will place the packet in the interface PBUF Queue for subsequent 
 * transmission when the transmitter becomes idle. 
 * 
 * @param netif the lwip network interface structure for this ethernetif 
 * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) 
 * @return ERR_OK if the packet could be sent 
 *         an err_t value if the packet couldn't be sent 
 * 
 */ 
static err_t 
low_level_output(struct netif *netif, struct pbuf *p) 
{ 
  struct ethernetif *ethernetif = netif->state; 
  SYS_ARCH_DECL_PROTECT(lev); 
 
  /** 
   * This entire function must run within a "critical section" to preserve 
   * the integrity of the transmit pbuf queue. 
   * 
   */ 
  SYS_ARCH_PROTECT(lev); 
 
  /** 
   * Bump the reference count on the pbuf to prevent it from being 
   * freed till we are done with it. 
   * 
   */ 
  pbuf_ref(p); 
 
  /** 
   * If the transmitter is idle, and there is nothing on the queue, 
   * send the pbuf now. 
   * 
   */ 
  if(PBUF_QUEUE_EMPTY(ðernetif->txq) && 
    ((HWREG(ETH_BASE + MAC_O_TR) & MAC_TR_NEWTX) == 0)) { 
    low_level_transmit(netif, p); 
  } 
 
  /* Otherwise place the pbuf on the transmit queue. */ 
  else { 
    /* Add to transmit packet queue */ 
    if(!enqueue_packet(p, &(ethernetif->txq))) { 
      /* if no room on the queue, free the pbuf reference and return error. */ 
      pbuf_free(p); 
      SYS_ARCH_UNPROTECT(lev); 
      return (ERR_MEM); 
    } 
  } 
 
  /* Return to prior interrupt state and return. */ 
  SYS_ARCH_UNPROTECT(lev); 
  return ERR_OK; 
} 
 
/** 
 * This function will read a single packet from the Stellaris ethernet 
 * interface, if available, and return a pointer to a pbuf.  The timestamp 
 * of the packet will be placed into the pbuf structure. 
 * 
 * @param netif the lwip network interface structure for this ethernetif 
 * @return pointer to pbuf packet if available, NULL otherswise. 
 */ 
static struct pbuf * 
low_level_receive(struct netif *netif) 
{ 
  struct pbuf *p, *q; 
  u16_t len; 
  u32_t temp; 
  int i; 
  unsigned long *ptr; 
 
  /* Check if a packet is available, if not, return NULL packet. */ 
  if((HWREG(ETH_BASE + MAC_O_NP) & MAC_NP_NPR_M) == 0) { 
    return(NULL); 
  } 
 
  /** 
   * Obtain the size of the packet and put it into the "len" variable. 
   * Note:  The length returned in the FIFO length position includes the 
   * two bytes for the length + the 4 bytes for the FCS. 
   * 
   */ 
  temp = HWREG(ETH_BASE + MAC_O_DATA); 
  len = temp & 0xFFFF; 
 
  /* We allocate a pbuf chain of pbufs from the pool. */ 
  p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); 
 
  /* If a pbuf was allocated, read the packet into the pbuf. */ 
  if(p != NULL) { 
    /* Place the first word into the first pbuf location. */ 
    *(unsigned long *)p->payload = temp; 
    p->payload = (char *)(p->payload) + 4; 
    p->len -= 4; 
 
    /* Process all but the last buffer in the pbuf chain. */ 
    q = p; 
    while(q != NULL) { 
      /* Setup a byte pointer into the payload section of the pbuf. */ 
      ptr = q->payload; 
 
      /** 
       * Read data from FIFO into the current pbuf 
       * (assume pbuf length is modulo 4) 
       * 
       */ 
      for(i = 0; i < q->len; i += 4) { 
        *ptr++ = HWREG(ETH_BASE + MAC_O_DATA); 
      } 
 
      /* Link in the next pbuf in the chain. */ 
      q = q->next; 
    } 
 
    /* Restore the first pbuf parameters to their original values. */ 
    p->payload = (char *)(p->payload) - 4; 
    p->len += 4; 
 
    /* Adjust the link statistics */ 
    LINK_STATS_INC(link.recv); 
  } 
 
  /* If no pbuf available, just drain the RX fifo. */ 
  else { 
    for(i = 4; i < len; i+=4) { 
      temp = HWREG(ETH_BASE + MAC_O_DATA); 
    } 
 
    /* Adjust the link statistics */ 
    LINK_STATS_INC(link.memerr); 
    LINK_STATS_INC(link.drop); 
  } 
 
  return(p); 
} 
 
/** 
 * This function should be called when a packet is ready to be read 
 * from the interface. It uses the function low_level_input() that 
 * should handle the actual reception of bytes from the network 
 * interface. Then the type of the received packet is determined and 
 * the appropriate input function is called. 
 * 
 * @param netif the lwip network interface structure for this ethernetif 
 */ 
int 
stellarisif_input(struct netif *netif) 
{ 
  struct ethernetif *ethernetif; 
  struct pbuf *p; 
  int count = 0; 
 
  ethernetif = netif->state; 
 
  /* move received packet into a new pbuf */ 
  while((p = dequeue_packet(ðernetif->rxq)) != NULL) { 
    count++; 
    /* process the packet. */ 
    if (ethernet_input(p, netif)!=ERR_OK) { 
      LWIP_DEBUGF(NETIF_DEBUG, ("stellarisif_input: input error\n")); 
      pbuf_free(p); 
      p = NULL; 
    } 
  } 
 
  return(count); 
} 
 
/** 
 * 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 netif 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 
 */ 
err_t 
stellarisif_init(struct netif *netif) 
{ 
  LWIP_ASSERT("netif != NULL", (netif != NULL)); 
 
#if LWIP_NETIF_HOSTNAME 
  /* Initialize interface hostname */ 
  netif->hostname = "lwip"; 
#endif /* LWIP_NETIF_HOSTNAME */ 
 
  /* 
   * Initialize the snmp variables and counters inside the struct netif. 
   * The last argument should be replaced with your link speed, in units 
   * of bits per second. 
   */ 
  NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 1000000); 
 
  netif->state = ðernetif_data; 
  netif->name[0] = IFNAME0; 
  netif->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...) */ 
  netif->output = etharp_output; 
  netif->linkoutput = low_level_output; 
 
  ethernetif_data.ethaddr = (struct eth_addr *)&(netif->hwaddr[0]); 
  ethernetif_data.txq.qread = ethernetif_data.txq.qwrite = 0; 
  ethernetif_data.txq.overflow = 0; 
  ethernetif_data.rxq.qread = ethernetif_data.rxq.qwrite = 0; 
  ethernetif_data.rxq.overflow = 0; 
 
  /* initialize the hardware */ 
  low_level_init(netif); 
 
  return ERR_OK; 
} 
 
/** 
 * Process tx and rx packets at the low-level interrupt. 
 * 
 * Should be called from the Stellaris Ethernet Interrupt Handler.  This 
 * function will read packets from the Stellaris Ethernet fifo and place them 
 * into a pbuf queue.  If the transmitter is idle and there is at least one packet 
 * on the transmit queue, it will place it in the transmit fifo and start the 
 * transmitter. 
 * 
 */ 
void 
stellarisif_interrupt(struct netif *netif) 
{ 
  struct ethernetif *ethernetif; 
  struct pbuf *p; 
 
  /* setup pointer to the if state data */ 
  ethernetif = netif->state; 
 
  /** 
   * Process the transmit and receive queues as long as there is receive 
   * data available 
   * 
   */ 
  p = low_level_receive(netif); 
  while(p != NULL) { 
    /* Add the rx packet to the rx queue */ 
    if(!enqueue_packet(p, ðernetif->rxq)) { 
      /* Could not place the packet on the queue, bail out. */ 
      pbuf_free(p); 
      break; 
    } 
 
    /* Check if TX fifo is empty and packet available */ 
    if((HWREG(ETH_BASE + MAC_O_TR) & MAC_TR_NEWTX) == 0) { 
      p = dequeue_packet(ðernetif->txq); 
      if(p != NULL) { 
        low_level_transmit(netif, p); 
      } 
    } 
 
    /* Read another packet from the RX fifo */ 
    p = low_level_receive(netif); 
  } 
 
  /* One more check of the transmit queue/fifo */ 
  if((HWREG(ETH_BASE + MAC_O_TR) & MAC_TR_NEWTX) == 0) { 
    p = dequeue_packet(ðernetif->txq); 
    if(p != NULL) { 
      low_level_transmit(netif, p); 
    } 
  } 
} 
 
#if NETIF_DEBUG 
/* Print an IP header by using LWIP_DEBUGF 
 * @param p an IP packet, p->payload pointing to the IP header 
 */ 
void 
stellarisif_debug_print(struct pbuf *p) 
{ 
  struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload; 
  u16_t *plen = (u16_t *)p->payload; 
 
  LWIP_DEBUGF(NETIF_DEBUG, ("ETH header:\n")); 
  LWIP_DEBUGF(NETIF_DEBUG, ("Packet Length:%5"U16_F" \n",*plen)); 
  LWIP_DEBUGF(NETIF_DEBUG, ("Destination: %02"X8_F"-%02"X8_F"-%02"X8_F"-%02"X8_F"-%02"X8_F"-%02"X8_F"\n", 
    ethhdr->dest.addr[0], 
    ethhdr->dest.addr[1], 
    ethhdr->dest.addr[2], 
    ethhdr->dest.addr[3], 
    ethhdr->dest.addr[4], 
    ethhdr->dest.addr[5])); 
  LWIP_DEBUGF(NETIF_DEBUG, ("Source: %02"X8_F"-%02"X8_F"-%02"X8_F"-%02"X8_F"-%02"X8_F"-%02"X8_F"\n", 
    ethhdr->src.addr[0], 
    ethhdr->src.addr[1], 
    ethhdr->src.addr[2], 
    ethhdr->src.addr[3], 
    ethhdr->src.addr[4], 
    ethhdr->src.addr[5])); 
  LWIP_DEBUGF(NETIF_DEBUG, ("Packet Type:0x%04"U16_F" \n", ethhdr->type)); 
} 
#endif /* NETIF_DEBUG */