ethernetif.c of LwIP

Introduction

  The network driver of LwIP has a certain model, and /src/netif/ethernetif.cthe file is the template of the driver. Users should refer to this module when implementing the driver for their own network devices. There can be multiple network interfaces in LwIP, and each network interface corresponds to one struct netif. This netif contains the properties and sending and receiving functions of the corresponding network interface.
  The functions in this file are usually functions that deal with hardware, and are called when data is received, so that the received data enters the tcpip protocol stack.

netif structure

  In LwIP, a hardware network interface is described by a structure netif. In a single network card, there is only one structure; in multiple network cards, there can be any netifstructure with the same number of network cards, and they constitute a data chain. The definition of this structure is in the file netif.h, as follows:

/** Generic data structure used for all lwIP network interfaces.
 *  The following fields should be filled in by the initialization
 *  function for the device driver: hwaddr_len, hwaddr[], mtu, flags */
struct netif {
  /** pointer to next in linked list */
  struct netif *next;

#if LWIP_IPV4
  /** IP address configuration in network byte order */
  ip_addr_t ip_addr;       /* IP 地址 */
  ip_addr_t netmask;       /* 子网掩码 */
  ip_addr_t gw;            /* 网关 */
#endif /* LWIP_IPV4 */
#if LWIP_IPV6
  /** Array of IPv6 addresses for this netif. */
  ip_addr_t ip6_addr[LWIP_IPV6_NUM_ADDRESSES];
  /** The state of each IPv6 address (Tentative, Preferred, etc).
   * @see ip6_addr.h */
  u8_t ip6_addr_state[LWIP_IPV6_NUM_ADDRESSES];
#endif /* LWIP_IPV6 */
  /** This function is called by the network device driver
   *  to pass a packet up the TCP/IP stack. */
  netif_input_fn input;   /* 函数指针,从网卡中接收一包数据 */
#if LWIP_IPV4
  /** This function is called by the IP module when it wants
   *  to send a packet on the interface. This function typically
   *  first resolves the hardware address, then sends the packet.
   *  For ethernet physical layer, this is usually etharp_output() */
  netif_output_fn output;   /* IP层调用此函数向网卡发送一包数据 */
#endif /* LWIP_IPV4 */
  /** This function is called by ethernet_output() when it wants
   *  to send a packet on the interface. This function outputs
   *  the pbuf as-is on the link medium. */
  netif_linkoutput_fn linkoutput;    /* ARP模块调用这个函数向网卡发送一包数据 */
#if LWIP_IPV6
  /** This function is called by the IPv6 module when it wants
   *  to send a packet on the interface. This function typically
   *  first resolves the hardware address, then sends the packet.
   *  For ethernet physical layer, this is usually ethip6_output() */
  netif_output_ip6_fn output_ip6;
#endif /* LWIP_IPV6 */
#if LWIP_NETIF_STATUS_CALLBACK
  /** This function is called when the netif state is set to up or down
   */
  netif_status_callback_fn status_callback;
#endif /* LWIP_NETIF_STATUS_CALLBACK */
#if LWIP_NETIF_LINK_CALLBACK
  /** This function is called when the netif link is set to up or down
   */
  netif_status_callback_fn link_callback;
#endif /* LWIP_NETIF_LINK_CALLBACK */
#if LWIP_NETIF_REMOVE_CALLBACK
  /** This function is called when the netif has been removed */
  netif_status_callback_fn remove_callback;
#endif /* LWIP_NETIF_REMOVE_CALLBACK */
  /** This field can be set by the device driver and could point
   *  to state information for the device. */
  void *state;          /* 这个成员变量注意以下,主要是将 网卡的某些私有数据传递给上层,用户可以自由发挥,也可以不用。下面会有详细说明。*/
#ifdef netif_get_client_data
  void* client_data[LWIP_NETIF_CLIENT_DATA_INDEX_MAX + LWIP_NUM_NETIF_CLIENT_DATA];
#endif
#if LWIP_IPV6_AUTOCONFIG
  /** is this netif enabled for IPv6 autoconfiguration */
  u8_t ip6_autoconfig_enabled;
#endif /* LWIP_IPV6_AUTOCONFIG */
#if LWIP_IPV6_SEND_ROUTER_SOLICIT
  /** Number of Router Solicitation messages that remain to be sent. */
  u8_t rs_count;
#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
#if LWIP_NETIF_HOSTNAME
  /* the hostname for this netif, NULL is a valid value */
  const char*  hostname;
#endif /* LWIP_NETIF_HOSTNAME */
#if LWIP_CHECKSUM_CTRL_PER_NETIF
  u16_t chksum_flags;
#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF*/
  /** maximum transfer unit (in bytes) */
  u16_t mtu;   /* 网络一次可以传送的最大字节数,对于以太网一般设为 1500 */
  /** number of bytes used in hwaddr */
  u8_t hwaddr_len;  /* 硬件地址长度,对于以太网就是 MAC 地址长度,为 6 各字节 */
  /** link level hardware address of this interface */
  u8_t hwaddr[NETIF_MAX_HWADDR_LEN];
  /** flags (@see @ref netif_flags) */
  u8_t flags;   /* 网卡状态信息标志位,是很重要的控制字段,它包括网卡功能使能、广播使能、 ARP 使能等等重要控制位。*/
  /** descriptive abbreviation */
  char name[2]; /* 字段用于保存每一个网络网络接口的名字。用两个字符的名字来标识网络接口使用的设备驱动的种类,名字由设备驱动来设置并且应该反映通过网络接口表示的硬件的种类。
  比如蓝牙设备( bluetooth)的网络接口名字可以是 bt,而 IEEE 802.11b WLAN 设备的名字就可以是 wl,当然设置什么名字用户是可以自由发挥的,这并不影响用户对网络接口的使用。
  当然,如果两个网络接口具有相同的网络名字,我们就用 num 字段来区分相同类别的不同网络接口。 */
  /** number of this interface */
  u8_t num;  /* 用来标示使用同种驱动类型的不同网络接口 */
#if MIB2_STATS
  /** link type (from "snmp_ifType" enum from snmp_mib2.h) */
  u8_t link_type;
  /** (estimate) link speed */
  u32_t link_speed;
  /** timestamp at last change made (up/down) */
  u32_t ts;
  /** counters */
  struct stats_mib2_netif_ctrs mib2_counters;
#endif /* MIB2_STATS */
#if LWIP_IPV4 && LWIP_IGMP
  /** This function could be called to add or delete an entry in the multicast
      filter table of the ethernet MAC.*/
  netif_igmp_mac_filter_fn igmp_mac_filter;
#endif /* LWIP_IPV4 && LWIP_IGMP */
#if LWIP_IPV6 && LWIP_IPV6_MLD
  /** This function could be called to add or delete an entry in the IPv6 multicast
      filter table of the ethernet MAC. */
  netif_mld_mac_filter_fn mld_mac_filter;
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
#if LWIP_NETIF_HWADDRHINT
  u8_t *addr_hint;
#endif /* LWIP_NETIF_HWADDRHINT */
#if ENABLE_LOOPBACK
  /* List of packets to be queued for ourselves. */
  struct pbuf *loop_first;
  struct pbuf *loop_last;
#if LWIP_LOOPBACK_MAX_PBUFS
  u16_t loop_cnt_current;
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
#endif /* ENABLE_LOOPBACK */
};

Each function

  In the template file provided by LwIP ethernetif.c, the following structure comes up:

struct ethernetif {
  struct eth_addr *ethaddr;
  /* Add whatever per-interface state that is needed here. */
};

  This structure is used to describe the underlying hardware device. The only indispensable part of this structure is the MAC address, which is the core data used by LWIP for corresponding ARP queries. If there is no special need, other member data may not be added. It is mainly used to pass some private data of the underlying hardware device netif ->stateto the upper layer ( ethernetif_initassignment in the function netif->state = ethernetif;). Generally do not need to change the structure. Because in the netifstructure, basically contains all the required information.
  ethernetif.cThe functions provided in the file mainly include the following:

  • static void low_level_init(struct netif *netif);
  • static struct pbuf * low_level_input(struct netif *netif);
  • static err_t low_level_output(struct netif *netif, struct pbuf *p);
  • void ethernetif_input( void * pvParameters )- low_level_output;
  • err_t ethernetif_init(struct netif *netif);

  The only external interface is ethernetif_initfunctions.

ethernetif_init

  This function completes the initialization of the network interface. It is called in the initialization function of LwIP netif_add( &EMAC_if, &xIpAddr, &xNetMast, &xGateway, NULL, ethernetif_init, tcpip_input );. See the following notes for details:

err_t ethernetif_init(struct netif *netif)
{
    LWIP_ASSERT("netif != NULL", (netif != NULL));

    #if LWIP_NETIF_HOSTNAME
    netif->hostname = "lwip";       /* Initialize interface hostname */
    #endif /* LWIP_NETIF_HOSTNAME */

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

    #if LWIP_IPV4
    #if LWIP_ARP || LWIP_ETHERNET
    #if LWIP_ARP
        netif->output = etharp_output;              /* 数据发送函数,其最终还是会调用 netif->linkoutput */
    #else
        /* The user should write ist own code in low_level_output_arp_off function */
        netif->output = low_level_output_arp_off;
    #endif /* LWIP_ARP */
    #endif /* LWIP_ARP || LWIP_ETHERNET */
    #endif /* LWIP_IPV4 */

    #if LWIP_IPV6 //0
        netif->output_ip6 = ethip6_output;
    #endif /* LWIP_IPV6 */
    netif->linkoutput = low_level_output;           /* 这个才是最底层发送函数(将数据交给硬件发送)*/

    /* initialize the hardware */
    low_level_init(netif);

//  etharp_init();

//  sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);

    return ERR_OK;
}

low_level_init

  This function is mainly to perform a series of initialization work on the network card, such as: initializing the MAC address, establishing the task of receiving data, etc.

low_level_input

  This function is responsible for receiving data from the network card. Normally apply for a pbuf structure from the LwIP buffer pool to store data.

ethernetif_input

  This function is the network card data receiving task. In LwIP, a task (ethernetif_input) polling checks the status of the DMA controller to determine whether data is received. The received data transmission process is as follows:
硬件接口取数 -> low_level_input -> tcpip_input(通过函数指针s_pxNetIf->input)

void ethernetif_input( void * pvParameters )
{
    struct pbuf *p;

    for( ;; )
    {
        /* 1. 该信号量会在网卡的中断中有数据时被发送 */
        if (xSemaphoreTake( s_xSemaphore, emacBLOCK_TIME_WAITING_FOR_INPUT)==pdTRUE)
        {
            TRY_GET_NEXT_FRAME:
            p = low_level_input( s_pxNetIf );                       /* 2. 从网卡中取数据 */
            if(p != NULL)   /* 有数据 */
            {
                /* 3. 将数据(pbuf的地址)传递到 TCP/IP协议栈(s_pxNetIf->input在netif_add函数中赋值为函数tcpip_input ) */
                if (ERR_OK != s_pxNetIf->input( p, s_pxNetIf))
                {
                    pbuf_free(p);
                }
                else
                {
                    goto TRY_GET_NEXT_FRAME;                        /* 4. 接收成功后,返回继续接收数据,直到网卡中没有数据了 */
                }
            }
            /* 5. 如果没有数据了,则会再次返回第 1 步收信号量 */
        }
    }
}

low_level_output

  The Output process is actively triggered by the application. In the TCP/IP protocol stack, the data to be sent is finally delivered to ip_output_if函数. Looking at the code, we can see that the function is called directly netif->output函数. In the above ethernetif_initfunction, there is an assignment to this variable [function pointer], which is etharp_output.
  The transfer process of the data to be sent is as follows:
ip_output_if -> etharp_output(通过函数指针netif->output)-> ethernet_output -> low_level_output(通过函数指针netif->linkoutput) -> 硬件设备

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325446724&siteId=291194637