您的位置:首页 > 其它

【lwip】lwip源码基础

2022-02-20 14:53 120 查看

[toc]

前言

本笔记记录 lwip 源码基础内容

李柱明博客:https://www.cnblogs.com/lizhuming/p/15487094.html

概念&作用

网络接口

概念引入

网络接口(以太网接口)是硬件接口(网络接口又可以称之为网卡)。

LWIP 是软件那么而怎样让硬件和软件无缝连接起来呢?

而且网卡又多种多样,怎样才能让 LWIP 使用同样的软件兼容不同的硬件平台?

LWIP 中使用了一个**

netif
**结构体来描述网卡但是网卡是直接和硬件平台打交道的:

  • 用户提供最底层接口函数。

  • LWIP 提供统一的 API。

  • 举例:

    收:如网卡的初始化和网卡的收发数据,当 LWIP 底层得到数据之后,才会传入到内核中去处理。
  • 发:LWIP 内核需要发送数据包的时候,也需要调用网卡的发送函数。
  • LWIP 中的 etherneif.c 文件的函数通常为硬件打交道的底层函数,当有数据需要通过网卡接收或者发送数据的时候就会被调用,通过 LWIP 的协议栈的内部进行处理后,从应用层就能得到数据或者可以发送数据。

  • 总结

    简单来说,netif 是 LWIP 抽象出来的网卡,LWIP 协议栈可以使用多种不同接口,而 etherneif.c 文件则提供了 netif 访问各种不同的网卡,每个网卡有不同的实方式,每户只需要修改 ethernetif.c 文件即可。

    lwip netif 结构体

    链接

    参考:LWIP中netif结构体的介绍

    源码:((20210727163318-nobqihq))

    字段分析

    网卡链表

    /** pointer to next in linked list */
    struct netif *next;

    LWIP 使用链表来统一管理同一设备的多个网卡。

    netif.c 文件中定义两个全局指针

    struct netif *netif_list
    struct netif *netif_default

    • netif_list
      就是网卡链表指针,指向网卡链表的首节点(第一个网卡)。
    • netif_default
      默认网卡。

    网络 IP

    #if LWIP_IPV4
    /** IP address configuration in network byte order */
    ip_addr_t ip_addr;
    ip_addr_t netmask;
    ip_addr_t gw;
    #endif /* LWIP_IPV4 */

    ip_addr
    :网络中的 IP 地址。

    netmask
    :子网掩码。

    gw
    :网关地址。

    接收数据函数

    /** This function is called by the network device driver
    *  to pass a packet up the TCP/IP stack. */
    netif_input_fn input;

    该函数由网络设备驱动程序调用,将数据包传递到 TCP/IP 协议栈(IP 层),这通常是

    ethernet_input()
    ,参数为
    pbuf
    netif
    类型,其中
    pbuf
    为接收到的数据包。

    发送数据函数

    #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;
    #endif /* LWIP_IPV4 */

    函数由 IP 层调用,在接口上发送数据包。用户需要编写该函数并使 output 指向它。

    通这个函数的处理步骤是首先解析硬件地址,然后发送数据包。

    对于以太网物理层,该函数通常是

    etharp_output()
    ,参数是
    pbuf
    ,
    netif
    ,和
    ip_addr
    类型。

    注意:其中

    ipaddr
    代表要将数据包发送到的地址,但不一定数据包最终到达的 ip 地址。比如要发送 ip 数据报到一个并不在本网络的主机上,该数据包要被发送到一个路由器上,这里的 ipaddr 就是路由器的 ip 地址。

    ARP 模块调用的发送函数

    /** 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;

    该函数和

    output
    类似,也需要用户自己实现一个函数,但是只有两个参数,它是由 ARP 模块调用的,一般是自定义函数
    low_level_output()

    当需要在网卡上发送一个数据包时,该函数会被

    ethernet_output()
    函数调用。

    出口回调函数

    #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 */

    当 netif 被删除时调用此函数。

    用户私有数据

    /** 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;

    链路硬件地址长度&地址

    /** number of bytes used in hwaddr */
    u8_t hwaddr_len;
    /** 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];

    用于保存每一个网卡的名字,用两个字符的名字来标识。

    网卡使用的设备驱动的种类,名字由设备驱动来设置并且应该反映通过网卡表示的硬件的种类。

    如果两个网卡具有相同的网络名字,我们就用 num 字段来区分相同类别的不同网卡。

    网卡标识

    /** number of this interface */
    u8_t num;

    标识使用同种驱动类型的不同网卡。

    netif 使用

    简要步骤:

    1. 定义一个

      netif
      作为网卡设备结构体。

    2. 挂载到

      netif_list
      链表中。

      使用函数:
      netif_add();
    3. 建议参考该函数源码。

    源码

    struct netif

    /** 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_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;
    #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;#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;/** number of bytes used in hwaddr */
    u8_t hwaddr_len;
    /** link level hardware address of this interface */
    u8_t hwaddr[NETIF_MAX_HWADDR_LEN];/** flags (@see @ref netif_flags) */
    u8_t flags;/** descriptive abbreviation */
    char name[2];/** 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 */
    };
    
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: