版本变更
2.1.x
LWIP 从 2.0.3 版本,直接跳到了 2.1.0 版本,又是一个大的版本更新。增加了一些功能!同时源码的目录结构也有了一定的变化(增加了一些文件)! 按照 LWIP 的发布策略,以后 2.1.x 都是从 2.1.0 版本开始的 BUG 修复版本,最新的 BUG 修复版本是 2.1.2。具体变化参见源码目录下的 CHANGELOG 文件。下图显示了 2.0.3 版 和 2.1.2 版的文件对比差异:
关于这个版本,官网有个这么一句话 “ Oh, and this will be the last release with a separate contrib repository. I’ll be merging the files from contrib into the main repository soon after the release. In the git world, having two separate repositories just doesn’t work nice. ” 。大意就是,这是带有独立 contrib 库的最后一版本,后续会将 contrib 合并到 LWIP 主版本库中。
其次,如果详细去看 LWIP 的说明文档,会发现文档中有些描述还是之前的,并没有跟随版本变更而改变!例如在doc目录下,原来的系统结构模板文件名为sys_arch.txt,在此版本没有了这个文件,但是说明文档中,仍然有这部分的介绍!
2.0.x
LWIP 从 1.4.1 版本,直接跳到了 2.0.x 版本,是一个大的版本更新。源码结构变化比较大! 按照 LWIP 的发布策略,以后 2.0.x 都是从 2.0.0 版本开始的 BUG 修复版本,最终的 BUG 修复版本是 2.0.3。2.0.3 版本修复自 2.0.2 以来的一些错误,没有任何功能的变化。具体如下:
2017-09-11: Simon Goldschmidt
tcp_in.c: fix bug #51937 (leaking tcp_pcbs on passive close with unacked data)
2017-08-02: Abroz Bizjak/Simon Goldschmidt
multiple fixes in IPv4 reassembly (leading to corrupted datagrams received)
2017-03-30: Simon Goldschmidt
dhcp.c: return ERR_VAL instead of asserting on offset-out-of-pbuf
2017-03-23: Dirk Ziegelmeier
dhcp.h: fix bug #50618 (dhcp_remove_struct() macro does not work)
最终版本为 1.4.1。
要使用 LWIP 的源码由两部分组成,分别为 LWIP 和 contrib 。这两个是由两个独立的版本库,并且由不同的人来负责的!我们在实际使用 LWIP 时,这两部分都是需要使用的!
其中,contrib 中是一些和平台移植相关的代码,LWIP 则是 TCP/IP 协议栈的核心源码!
下面我就以 2.0.3 版为例!从 1.4.1 到 2.0.3(从 2.0.0 开始),LwIP 的源码有了一定的变化,甚至于源码的文件结构也不一样,内部的一些实现源文件也被更新和替换了。其源码目录结构如下所示(对于简单的文件以注释的形式给出,核心源码下文会详细说明):
LWIP-2.0.3
│ CHANGELOG // 版本更新记录,从中可以看到 LwIP 不同版本的变化
│ COPYING // 版权说明
│ FILES // 其中说明了其所在目录下的各目录或文件的用途。在不同的目录下会有不同的该文件
│ README // 简介文档
│ UPGRADING // 版本升级后可能出现不兼容,该文档记录了从老版本升级需要修改的地方。对于升级自己使用的 LwIP 版本时很有用处。
├─doc
│ │ contrib.txt // LwIP 作为开源软件,如果想要为其做贡献,则需要遵循一定的准则,例如:提交代码的风格、报告Bug等。该文档给出了详细的贡献准则。
│ │ doxygen_docs.zip // 用 doxygen 生成的 LwIP 的配套文档
│ │ FILES // 其中说明了该目录下的每个文件的用途
│ │ mdns.txt // MDNS 的说明文档
│ │ mqtt_client.txt
│ │ NO_SYS_SampleCode.c
│ │ ppp.txt // lwIP的PPP接口文档
│ │ rawapi.txt // 告诉读者怎样使用协议栈的 Raw/Callback API 进行编程
│ │ savannah.txt // 说明了如何获取当前的开发源代码
│ │ sys_arch.txt // 在有操作系统的移植的时候会被使用到,包含了移植说明,规定了移植者需要实现的函数、宏定义等,后面有详细说明。
│ └─doxygen // doxygen 脚本,主要用来维护 LwIP 的配套文档。对于使用LwIP来说用不到
│ │ generate.bat
│ │ generate.sh
│ │ lwip.Doxyfile
│ │ main_page.h
│ └─output
│ index.html
├─src /* 源码文件部分下面独立详细说明 */
│ │ Filelists.mk
│ │ FILES // 主要记录了该目录下每个文件、目录的用途
│ ├─api
│ │ api_lib.c
│ │ api_msg.c
│ │ err.c
│ │ netbuf.c
│ │ netdb.c
│ │ netifapi.c
│ │ sockets.c
│ │ tcpip.c
│ ├─apps
│ │ ├─httpd
│ │ │ │ fs.c
│ │ │ │ fsdata.c
│ │ │ │ fsdata.h
│ │ │ │ httpd.c
│ │ │ │ httpd_structs.h
│ │ │ ├─fs
│ │ │ │ │ 404.html
│ │ │ │ │ index.html
│ │ │ │ └─img
│ │ │ │ sics.gif
│ │ │ └─makefsdata
│ │ │ makefsdata
│ │ │ makefsdata.c
│ │ │ readme.txt
│ │ ├─lwiperf
│ │ │ lwiperf.c
│ │ ├─mdns
│ │ │ mdns.c
│ │ ├─mqtt
│ │ │ mqtt.c
│ │ ├─netbiosns
│ │ │ netbiosns.c
│ │ ├─snmp
│ │ │ snmpv3.c
│ │ │ snmpv3_dummy.c
│ │ │ snmpv3_mbedtls.c
│ │ │ snmpv3_priv.h
│ │ │ snmp_asn1.c
│ │ │ snmp_asn1.h
│ │ │ snmp_core.c
│ │ │ snmp_core_priv.h
│ │ │ snmp_mib2.c
│ │ │ snmp_mib2_icmp.c
│ │ │ snmp_mib2_interfaces.c
│ │ │ snmp_mib2_ip.c
│ │ │ snmp_mib2_snmp.c
│ │ │ snmp_mib2_system.c
│ │ │ snmp_mib2_tcp.c
│ │ │ snmp_mib2_udp.c
│ │ │ snmp_msg.c
│ │ │ snmp_msg.h
│ │ │ snmp_netconn.c
│ │ │ snmp_pbuf_stream.c
│ │ │ snmp_pbuf_stream.h
│ │ │ snmp_raw.c
│ │ │ snmp_scalar.c
│ │ │ snmp_table.c
│ │ │ snmp_threadsync.c
│ │ │ snmp_traps.c
│ │ ├─sntp
│ │ │ sntp.c
│ │ └─tftp
│ │ tftp_server.c
│ ├─core
│ │ │ def.c
│ │ │ dns.c
│ │ │ inet_chksum.c
│ │ │ init.c
│ │ │ ip.c
│ │ │ mem.c
│ │ │ memp.c
│ │ │ netif.c
│ │ │ pbuf.c
│ │ │ raw.c
│ │ │ stats.c
│ │ │ sys.c
│ │ │ tcp.c
│ │ │ tcp_in.c
│ │ │ tcp_out.c
│ │ │ timeouts.c
│ │ │ udp.c
│ │ ├─ipv4
│ │ │ autoip.c
│ │ │ dhcp.c
│ │ │ etharp.c
│ │ │ icmp.c
│ │ │ igmp.c
│ │ │ ip4.c
│ │ │ ip4_addr.c
│ │ │ ip4_frag.c
│ │ └─ipv6
│ │ dhcp6.c
│ │ ethip6.c
│ │ icmp6.c
│ │ inet6.c
│ │ ip6.c
│ │ ip6_addr.c
│ │ ip6_frag.c
│ │ mld6.c
│ │ nd6.c
│ ├─include
│ │ ├─lwip
│ │ │ │ api.h
│ │ │ │ arch.h
│ │ │ │ autoip.h
│ │ │ │ debug.h
│ │ │ │ def.h
│ │ │ │ dhcp.h
│ │ │ │ dhcp6.h
│ │ │ │ dns.h
│ │ │ │ err.h
│ │ │ │ errno.h
│ │ │ │ etharp.h
│ │ │ │ ethip6.h
│ │ │ │ icmp.h
│ │ │ │ icmp6.h
│ │ │ │ igmp.h
│ │ │ │ inet.h
│ │ │ │ inet_chksum.h
│ │ │ │ init.h
│ │ │ │ ip.h
│ │ │ │ ip4.h
│ │ │ │ ip4_addr.h
│ │ │ │ ip4_frag.h
│ │ │ │ ip6.h
│ │ │ │ ip6_addr.h
│ │ │ │ ip6_frag.h
│ │ │ │ ip_addr.h
│ │ │ │ mem.h
│ │ │ │ memp.h
│ │ │ │ mld6.h
│ │ │ │ nd6.h
│ │ │ │ netbuf.h
│ │ │ │ netdb.h
│ │ │ │ netif.h
│ │ │ │ netifapi.h
│ │ │ │ opt.h
│ │ │ │ pbuf.h
│ │ │ │ raw.h
│ │ │ │ sio.h
│ │ │ │ snmp.h
│ │ │ │ sockets.h
│ │ │ │ stats.h
│ │ │ │ sys.h
│ │ │ │ tcp.h
│ │ │ │ tcpip.h
│ │ │ │ timeouts.h
│ │ │ │ udp.h
│ │ │ ├─apps
│ │ │ │ FILES
│ │ │ │ fs.h
│ │ │ │ httpd.h
│ │ │ │ httpd_opts.h
│ │ │ │ lwiperf.h
│ │ │ │ mdns.h
│ │ │ │ mdns_opts.h
│ │ │ │ mdns_priv.h
│ │ │ │ mqtt.h
│ │ │ │ mqtt_opts.h
│ │ │ │ netbiosns.h
│ │ │ │ netbiosns_opts.h
│ │ │ │ snmp.h
│ │ │ │ snmpv3.h
│ │ │ │ snmp_core.h
│ │ │ │ snmp_mib2.h
│ │ │ │ snmp_opts.h
│ │ │ │ snmp_scalar.h
│ │ │ │ snmp_table.h
│ │ │ │ snmp_threadsync.h
│ │ │ │ sntp.h
│ │ │ │ sntp_opts.h
│ │ │ │ tftp_opts.h
│ │ │ │ tftp_server.h
│ │ │ ├─priv
│ │ │ │ api_msg.h
│ │ │ │ memp_priv.h
│ │ │ │ memp_std.h
│ │ │ │ nd6_priv.h
│ │ │ │ tcpip_priv.h
│ │ │ │ tcp_priv.h
│ │ │ └─prot
│ │ │ autoip.h
│ │ │ dhcp.h
│ │ │ dns.h
│ │ │ etharp.h
│ │ │ ethernet.h
│ │ │ icmp.h
│ │ │ icmp6.h
│ │ │ igmp.h
│ │ │ ip.h
│ │ │ ip4.h
│ │ │ ip6.h
│ │ │ mld6.h
│ │ │ nd6.h
│ │ │ tcp.h
│ │ │ udp.h
│ │ ├─netif
│ │ │ │ etharp.h
│ │ │ │ ethernet.h
│ │ │ │ lowpan6.h
│ │ │ │ lowpan6_opts.h
│ │ │ │ slipif.h
│ │ │ └─ppp
│ │ │ │ ccp.h
│ │ │ │ chap-md5.h
│ │ │ │ chap-new.h
│ │ │ │ chap_ms.h
│ │ │ │ eap.h
│ │ │ │ ecp.h
│ │ │ │ eui64.h
│ │ │ │ fsm.h
│ │ │ │ ipcp.h
│ │ │ │ ipv6cp.h
│ │ │ │ lcp.h
│ │ │ │ magic.h
│ │ │ │ mppe.h
│ │ │ │ ppp.h
│ │ │ │ pppapi.h
│ │ │ │ pppcrypt.h
│ │ │ │ pppdebug.h
│ │ │ │ pppoe.h
│ │ │ │ pppo.h
│ │ │ │ pppos.h
│ │ │ │ ppp_impl.h
│ │ │ │ ppp_opts.h
│ │ │ │ upap.h
│ │ │ │ vj.h
│ │ │ └─polarssl
│ │ │ arc4.h
│ │ │ des.h
│ │ │ md4.h
│ │ │ md5.h
│ │ │ sha1.h
│ │ └─posix
│ │ │ errno.h
│ │ │ netdb.h
│ │ └─sys
│ │ socket.h
│ └─netif
│ │ ethernet.c
│ │ ethernetif.c
│ │ FILES
│ │ lowpan6.c
│ │ slipif.c
│ └─ppp
│ │ auth.c
│ │ ccp.c
│ │ chap-md5.c
│ │ chap-new.c
│ │ chap_ms.c
│ │ demand.c
│ │ eap.c
│ │ ecp.c
│ │ eui64.c
│ │ fsm.c
│ │ ipcp.c
│ │ ipv6cp.c
│ │ lcp.c
│ │ magic.c
│ │ mppe.c
│ │ multilink.c
│ │ ppp.c
│ │ pppapi.c
│ │ pppcrypt.c
│ │ PPPD_FOLLOWUP
│ │ pppoe.c
│ │ pppo.c
│ │ pppos.c
│ │ upap.c
│ │ utils.c
│ │ vj.c
│ └─polarssl
│ arc4.c
│ des.c
│ md4.c
│ md5.c
│ README
│ sha1.c
└─test // 一些协议栈内核测试程序.在实际使用时一般用不到!可直接删除。
├─fuzz
│ │ config.h
│ │ fuzz.c
│ │ lwipopts.h
│ │ Makefile
│ │ output_to_pcap.sh
│ │ README
│ └─inputs
│ ├─arp
│ │ arp_req.bin
│ ├─icmp
│ │ icmp_ping.bin
│ ├─ipv6
│ │ neighbor_solicitation.bin
│ │ router_adv.bin
│ ├─tcp
│ │ tcp_syn.bin
│ └─udp
│ udp_port_5000.bin
└─unit
│ lwipopts.h
│ lwip_check.h
│ lwip_unittests.c
├─core
│ test_mem.c
│ test_mem.h
│ test_pbuf.c
│ test_pbuf.h
├─dhcp
│ test_dhcp.c
│ test_dhcp.h
├─etharp
│ test_etharp.c
│ test_etharp.h
├─ip4
│ test_ip4.c
│ test_ip4.h
├─mdns
│ test_mdns.c
│ test_mdns.h
├─tcp
│ tcp_helper.c
│ tcp_helper.h
│ test_tcp.c
│ test_tcp.h
│ test_tcp_oos.c
│ test_tcp_oos.h
└─udp
test_udp.c
test_udp.h
LwIP 提供了两种类型的 API : Callback-style APIs 和 Sequential-style APIs 。其中,Callback-style APIs 即为LwIP最底层的接口,被称为Raw API或者Native API;而Sequential-style APIs主要是对底层接口进行了封装,主要包含:Netconn API、NETIF API和Socket API。在实际使用中,使用者可以任选一种API来使用。
api目录下主要包含对底层API(raw API)封装后的高级API的代码。 如果直接使用底层的的Raw API,则不需要该目录下的文件。而封装后的高级别的这两种API实现的原理都是通过引进邮箱和信号量等通信与同步机制,来实现对内核中***Raw API(native API)***函数的封装和调用。要使用这两种类型的API,需要底层操作系统的支持。
Netconn API: 为普通的、顺序的程序提供了使用lwIP栈的方法。 线程安全,仅从非TCPIP线程调用。 基于网络缓冲区(包含数据包缓冲区(PBUF))的TX / RX处理,以避免复制数据。这与BSD Socket API非常相似。 执行模型基于 打开-读取-写入-关闭 范例。 由于TCP / IP堆栈本质上是事件,所以TCP / IP代码和应用程序必须驻留在不同的执行上下文(线程)中。
Socket API: 它是建立在Netconn API之上的。其主要是由于BSD Socket API是网络通信的一个实现。线程安全,仅从非TCPIP线程调用。BSD Socket API已经是网络套接字的事实上的抽象标准。目前,所有主流操作系统均实现了BSD Socket API。出于此,LwIP也提供了一套BSD Socket API。但是,标准 socket 库中的部分函数仍无法直接通过封装 Netconn API 来实现,因此 LwIP 中提供的socket 函数并不完整,用户最好不要使用它进行实际应用程序开发。对应文件为posix/sys/socket.h。
api_lib.c: 包含 对外提供的 sequential API 函数的实现。函数名均以netconn_开头。主要分为三组API:同时可用于TCP和UDP的API、只能用于TCP的API、只能用于UDP的API。
api_msg.c: 包含sequential API内部自己调用的函数的实现。主要包含API消息的封装和处理函数
err.c: 错误管理模块
netbuf.c: 包含了上层数据包管理函数的实现。应用程序描述待发送数据和已接收数据的基本结构。该结构只是对内核 pbuf 的简单封装,避免了数据的拷贝。缓冲区不能在多个线程之间共享。
netdb.c: 包含与主机名字转换相关的函数,主要在 socket 中被使用到
netifapi.c: 包含了上层网络接口管理函数的实现
sockets.c: 包含了 Socket API 函数的实现
tcpip.c: 包含了上层 API 与协议栈内核交互的函数,它是整个上层 API 功能得以实现的一个枢纽,其实现的功能可以简单理解为:从 API 函数处接收消息,然后将消息递交给内核函数,内核函数根据消息做出相应的处理。
使用lwIP低级raw API编写的高层应用程序。
TCP/IP 协议栈的核心部分。主要包含协议实现、内存和缓冲区管理以及底层raw API的实现。它包含了IP、ICMP、IGMP、TCP、UDP 等核 心协议以及建立在它们基础上的 DNS、DHCP、SNMP 等上层应用协议。内核源代码可以单独运行,且不需要操作系统的支持。即:直接使用 raw API 编程。
其他文件与IPv4目录下的功能相同,不过是在IPv6版上的实现
在2.0.0之前的版本中,该文件名为timer.c。新的timeouts.c对原来的内容进行了一定的封装,简化。
LwIP使用的各种头文件。与各源码目录相对应。