LWIP协议栈架构与设计解析_第1页
LWIP协议栈架构与设计解析_第2页
LWIP协议栈架构与设计解析_第3页
LWIP协议栈架构与设计解析_第4页
LWIP协议栈架构与设计解析_第5页
已阅读5页,还剩17页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、LWIP协议栈及接口提取Version 1.02012/06/201 / 21 第 1 页 共 21 页版本1.0姓名部门邮件作者雷岩Leiyan3521审阅2 / 21 第 2 页 共 21 页版本历史版本日期修订姓名Rev 1.02011/11/07First Draftleiyan 3 / 21 第 3 页 共 21 页目录一、LWIP介绍5二、LWIP源码分析71LWIP协议栈的架构72各个文件夹介绍83模块及源文件介绍10三、LWIP协议栈处理数据流程17四、接口提取184 / 21 第 4 页 共 21 页一、 LWIP介绍首先说明一下,这篇文档的主要目的是提取网络发送和接收数据的

2、函数接口。然后用我们自己的驱动网卡的接口函数替代程序中的接口。如果对LWIP协议栈本身没什么兴趣的,可以跳过第一、二、三章,直接阅读第四章,使用我们的接口代替第四章的接口就行了。写第一、二、三章的主要目的是为了方便理解数据的发送和接收在LWIP协议栈中是如何进行处理的。这便于我们理解提取出来的接口。LWIP是瑞典计算机科学院开发的一套用于嵌入式系统的开放源代码的轻量级的TCP/IP协议栈。传统的,或者说是典型的TCP/IP协议族的设计都是按照分层的思想来设计的。这样设计有个好处,就是每层相对于其他层独立,代码方便理解。缺点就是,每层之间进行数据交互的时候必须要进行复制,而数据的复制是很耗时的,

3、这就降低了实时性。LWIP采用了一种不同的设计方式来实现TCP/IP协议族。LWIP各层之间没有明显的界限,各层之间都可以访问到共享在内存中的数据。因为各层都可以访问共享内存,所以这就避免了内存复制产生的性能损失。但是并不是说LWIP就没有分层的概念了。只不过LWIP各层都是逻辑意义上的层。每个协议都以模块的形式被实现。而这些模块就共同组成了LWIP整体。下面一章将分析LWIP的源码,结合源码介绍这些模块。了解各个协议是怎么通过模块被实现的。其中这里最主要的是TCP协议模块的实现。TCP协议在LWIP协议栈中占得比例最大,有将近一半的代码是专门用来实现TCP协议的。所以重点会分析TCP协议。并

4、且无线音频项目采用的也是TCP协议传输数据。LWIP逻辑上被分为四个层:应用层,传输层,网络层和网络接口层。如下图1.1所示:5 / 21 第 5 页 共 21 页图1.1LWIP协议栈的分层模型应用层主要是使用LWIP协议栈开发相应的网络通信程序。LWIP主要提供了三种接口供用户使用。三种接口分别为RAW API, Netconn API 和 BSD Socket AP。其中RAW API 主要是采用回调函数的方式来完成数据的发送和接收,RAW API 接口写的应用程序与 LWIP协议栈处在同一个进程(或者称任务)中。Netconn API 和 BSD Socket AP工作于多线程方式中,

5、要使用者两种接口,必须有多任务的操作系统的支持。这次项目采用的接口是RAW API。关于RAW API接口如何写应用层程序,另写了一个专门的文档介绍。这里不列出。传输层。我们最熟悉的TCP 协议,UDP协议,以及我们使用ping 命令时采用的ICMP协议都处在这一层。这一层提供了一些专门的接口,用于处理与应用层和网络层的数据传送(注明,这里说的数据传送并不是指数据的拷贝。事实上,LWIP协议栈使用的是内存共享技术,各层都能访问这段共享内存,各层传递的就是数据结构指针,所以LWIP协议栈降低了内存复制所产生的性能损失)。关于这层函数,会在下面进行具体说明。网络层主要的协议是IP协议。这一层主要是

6、对底层接收的数据包进行发送,转发,丢弃组合等功能。网络接口层是和底层硬件驱动交互的层。我们所需要提取的网络接口就在这一层。6 / 21 第 6 页 共 21 页二、 LWIP源码分析1 LWIP协议栈的架构LWIP协议栈源码的架构如下图2.1所示:图2.1 LWIP协议栈源码架构api目录:应用程序接口文件,包括netconn 和BSD 2种API。这个文件夹主要是为了方便应用程序编写而为应用层提供的API接口。core 目录:ICMP,IP,TCP,UDP协议的实现文件,以及一些辅助函数,LWIP实现的核心代码。其中这个文件夹里面实现TCP协议的代码量几乎占了整个lwip协议栈的一半。重点会

7、讨论TCP协议。在此也可以简单看出LWIP协议栈没有严格区分传输层和网络层,因为传输层的代码和网络层的代码放在一个文件夹里实现了。目录里还提供了RAW API接口的实现。RAW API 接口和上面两种接口一样,都是为了方便应用程序编写而为应用层提供的API接口。include 目录:主要是LWIP协议栈使用的自定义的一些头文件。netif 目录:这个目录里主要实现的是ARP协议。当然还有一些PPPOE等协议。当然PPPOE协议不是我们所关心的。port 目录:最后写这个目录,主要是因为这个目录是我们最终所要修改的一个目录。可以看到此目录下包含一个ethernetif.c 文件。这个文件提供了与

8、底层网络驱动的一个接口。我们要实现与自己的网络接口驱动交互,必须修改这个文件里的接口,使这些接口为上层屏蔽细节信息。7 / 21 第 7 页 共 21 页2各个文件夹介绍【1】api目录,如图2.2图2.2 api目录下的文件列表这个文件夹下面主要提供的是netconn API 和BSD socket API 。这些接口不是我们所要关心的。所以直接忽略。我们使用下面文件夹里提供的RAW API 接口。【2】core 目录,如图2.3图2.3core目录下的文件列表这个文件下下面,ipv6文件夹和snmp文件夹我们不需要关心。主要关心的文件有icmp.c Ip.c ip_addr.c ip_fr

9、ag.c dhcp.c init.c mem.c memp.c netif.c pbuf.c9 / 21 第 9 页 共 21 页Raw.c tcp.c tcp_in.c tcp_out.c udp.c【3】include 目录,如图2.4图2.4include目录下的文件列表这个文件夹下面主要包括所有.c文件用到的头文件。Ipv6文件夹我们不必关心。【4】netif 目录,如图2.5图2.5netif目录下的文件列表这个文件夹下面主要关心etharp.c 这个文件其余的不必关心。其中文件夹PPP是关于点对点协议的,不必关心【5】port 目录,如图2.69 / 21 第 9 页 共 21 页

10、图2.6port目录下的文件列表这个文件夹下面关于arch 目录,这个目录是移植时候主要修改的目录。这个目录下包含的是与体系结构相关的一些定义等。FreeRTOS这个文件夹不需要关心,因为这是基于实时操作系统的,而我们现在做的项目是基于单任务的,无需操作系统的支持。Standalone这个文件夹下面的ethernetif.c中给出的驱动接口。我们为自己的网络接口设计的驱动程最终用来代替这个文件里的接口。上面所有文件大致描述了LWIP协议栈的几个模块:配置模块、初始化模块、NetIf模块、Mem(memp)模块、netarp模块、ip模块、udp模块、icmp 模块、igmp模块和dhcp模块。

11、由于篇幅限制,不能对每个源文件都做介绍。只对我们感兴趣的模块的源文件做相应的介绍。3模块及源文件介绍【1】配置模块配置模块的文件主要包含在include/lwip/opt.h里(这里及下文所指的路径均为相对路径)。配置模块通过各种宏定义的方式对系统、子模块进行了配置。比如,通过宏,配置了mem管理模块的参数。该配置模块还通过宏,配置了协议栈所支持的协议簇,通过宏定制的方式,决定了支持那些协议。/* * LWIP_ARP=1: Enable ARP functionality. */#ifndef LWIP_ARP#define LWIP_ARP 1#endif截取一段代码说明问题。上面的代码表

12、示配置的时候支持ARP(地址解析协议)协议族,此代码下面对ARP协议族进行一些其他的配置。10 / 21 第 10 页 共 21 页【2】初始化模块初始化模块(这里主要讲的是TCP协议的初始化模块)主要在文件 api/tcpip.c中。贴上源代码voidtcpip_init(void (* initfunc)(void *), void *arg) lwip_init(); tcpip_init_done = initfunc; tcpip_init_done_arg = arg; mbox = sys_mbox_new(TCPIP_MBOX_SIZE);#if LWIP_TCPIP_CORE

13、_LOCKING lock_tcpip_core = sys_sem_new(1);#endif /* LWIP_TCPIP_CORE_LOCKING */ sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);这个初始化模块是如此的重要,以至于我们可以说这是整个程序的核心。首先调用lwip_init()初始化了所有的子模块。然后调用sys_thread_new()启动了协议栈管理进程。所有的程序就在tcpip_thread这个进程里运行(这里说的是使用R

14、AW API接口的情况)。【3】NetIf模块netif 模块是非常重要的一个模块,主要是因为里面有一个netif 的结构体。Netif模块为协议栈与底层驱动的接口模块,其将底层的一个网口设备描述成协议栈的一个接口设备(net interface)。这个接口设备就是用上面说的netif结构体来描述。所以说neitif结构体很重要。Netif模块主要文件为core/netif.c 和 include/lwip/netif.h。struct netif /* pointer to next in linked list */ struct netif *next; /* IP address co

15、nfiguration in network byte order */ struct ip_addr ip_addr; struct ip_addr netmask;11 / 21 第 11 页 共 21 页 struct ip_addr gw; /* This function is called by the network device driver * to pass a packet up the TCP/IP stack. */ err_t (* input)(struct pbuf *p, struct netif *inp); /* This function is call

16、ed 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. */ err_t (* output)(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr); /* This function is called by the ARP module when it wants *

17、to send a packet on the interface. This function outputs * the pbuf as-is on the link medium. */ err_t (* linkoutput)(struct netif *netif, struct pbuf *p);#if LWIP_NETIF_STATUS_CALLBACK /* This function is called when the netif state is set to up or down */ void (* status_callback)(struct netif *net

18、if);#endif /* LWIP_NETIF_STATUS_CALLBACK */#if LWIP_NETIF_LINK_CALLBACK /* This function is called when the netif link is set to up or down */ void (* link_callback)(struct netif *netif);#endif /* LWIP_NETIF_LINK_CALLBACK */ /* This field can be set by the device driver and could point * to state in

19、formation for the device. */ void *state;#if LWIP_DHCP /* the DHCP client state information for this netif */ struct dhcp *dhcp;#endif /* LWIP_DHCP */#if LWIP_AUTOIP /* the AutoIP client state information for this netif */ struct autoip *autoip;#endif#if LWIP_NETIF_HOSTNAME /* the hostname for this

20、netif, NULL is a valid value */ char* hostname;#endif /* LWIP_NETIF_HOSTNAME */ /* 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 */12 / 21 第 12 页 共 21 页 u8_t hwaddrNETIF_MAX_HWADDR_LEN; /* flags (

21、see NETIF_FLAG_ above) */ u8_t flags; /* descriptive abbreviation */ char name2; /* number of this interface */ u8_t num;#if LWIP_SNMP /* link type (from snmp_ifType enum from snmp.h) */ u8_t link_type; /* (estimate) link speed */ u32_t link_speed; /* timestamp at last change made (up/down) */ u32_t

22、 ts; /* counters */ u32_t ifinoctets; u32_t ifinucastpkts; u32_t ifinnucastpkts; u32_t ifindiscards; u32_t ifoutoctets; u32_t ifoutucastpkts; u32_t ifoutnucastpkts; u32_t ifoutdiscards;#endif /* LWIP_SNMP */#if LWIP_IGMP /* This function could be called to add or delete a entry in the multicast filt

23、er table of the ethernet MAC.*/ err_t (*igmp_mac_filter)( struct netif *netif, struct ip_addr *group, u8_t action);#endif /* LWIP_IGMP */#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

24、_first; struct pbuf *loop_last;#if LWIP_LOOPBACK_MAX_PBUFS u16_t loop_cnt_current;#endif /* LWIP_LOOPBACK_MAX_PBUFS */#endif /* ENABLE_LOOPBACK */;这个结构体里所有的成员的作用都已经注释了,这里我们只关心两个成员:13 / 21 第 13 页 共 21 页err_t (* input)(struct pbuf *p, struct netif *inp);err_t (* output)(struct netif *netif, struct pbu

25、f *p,当收到一个信息包时,设备驱动程序调用input 指针指向的函数。网络接口通过output 指针连接到设备驱动。这个指针指向设备驱动中一个向物理网络发送信息包的函数,当信息包被发送时由IP 层调用。这个字段由设备驱动的初始设置函数填充。也就是说,当我们从网络上接收一个数据的时候我们调用input函数指针指向的函数进行数据接收的处理。当我们要向网络中发送一个数据时,我们调用output函数指针指向的那个函数进行数据的发送工作。因为这个netif结构体是与底层驱动进行交互的。所以input 和output 函数指针是直接指向网络驱动收发接口函数的。回到netif.c文件中,netif.c文

26、件通过链表的方式描述了系统中的所有网口设备。因为系统中可能会有很多网络设备。【4】Mem(memp)模块其实mem 和memp管理的是不同类型的内存,但都属于内存管理。所以放在了一起。Mem模块同一管理了协议栈使用的内容缓冲区,并管理pbuf结构以及报文的字段处理。主要的文件包括mem.c、memp.c、pbuf.c。这里我们所要关心的是内存管理单元所管理的pbuf结构体。typedef enum PBUF_RAM, /* pbuf data is stored in RAM */ PBUF_ROM, /* pbuf data is stored in ROM */ PBUF_REF, /*

27、pbuf comes from the pbuf pool */ PBUF_POOL /* pbuf payload refers to RAM */ pbuf_type;如上所示,pbuf有四种类型(但是文档中只介绍了三种类型)。关于这四种类型的pbuf有什么区别请参考相应的文档,一句话说明四者的不同,主要是pbuf结构体中存放的数据的位置不同。一句话说明pbuf类型的选择。当接收网络数据包时,我们选择的pbuf是PBUF_POOL类型的。至于网络数据包的发送,根据自己的实际情况自己选择。struct pbuf *pbuf_alloc(pbuf_layer l, u16_t size, pb

28、uf_type type);void pbuf_realloc(struct pbuf *p, u16_t size); u8_t pbuf_header(struct pbuf *p, s16_t header_size);14 / 21 第 14 页 共 21 页void pbuf_ref(struct pbuf *p);void pbuf_ref_chain(struct pbuf *p);u8_t pbuf_free(struct pbuf *p);u8_t pbuf_clen(struct pbuf *p); void pbuf_cat(struct pbuf *head, stru

29、ct pbuf *tail);void pbuf_chain(struct pbuf *head, struct pbuf *tail);struct pbuf *pbuf_dechain(struct pbuf *p);err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from);u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset);err_t pbuf_take(struct pbuf *buf, const void *dataptr

30、, u16_t len);struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer);这是对pbuf结构体进行操作的函数。【5】netarp模块netarp模块是处理arp协议的模块,主要源文件为netif/etharp.c。其主要入口函数为:err_t ethernet_input(struct pbuf *p, struct netif *netif)该入口函数通过判断输入报文p的协议类型来决定是按照arp协议进行处理还是将该报文提交到IP协议。如果报文是arp报文,该接口则调用etharp_arp_input,进行arp请求处

31、理。如果是ip报文,该接口就调用etharp_ip_input进行arp更新,并调用ip_input接口,将报文提交给ip层。在该模块中,创建了设备的地址映射arp表,并提供地址映射关系查询接口。同时还提供了arp报文的发送接口。如下:err_t etharp_output(struct netif *netif, struct pbuf *q, struct ip_addr *ipaddr)该接口需要注册到netif的output字段,ip层在输出报文时,通过该接口获取目标机的MAC地址,组合最终报文后,由该接口调用底层设备的驱动接口发送数据。在etharp_output接口中,判断报文类型

32、,如果是广播包或者组播包,就调用etharp_send_ip(组装目标mac和源mac)接口,etharp_send_ip调用netif结构中的设备驱动注册的linkoutput钩子函数发送最终报文。如果是单播包,etharp_output接口就调用etharp_query进行ip地址和MAC地址的映射,来获取到目标机的MAC地址。并在etharp_query中调用etharp_send_ip来发送最终组合报文。【6】ip模块ip模块实现了协议的ip层处理,主要文件为ipv4/ip.c。其主要入口函数为:err_t ip_input(struct pbuf *p, struct netif *

33、inp)该接口通过判断输入报文的协议类型,将其输入到相应的上层协议模块中去。比如,将udp报文送到udp_input。该模块另外一个接口是输入函数,原型如下:err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, u8_t ttl, u8_t tos, u8_t proto)15 / 21 第 15 页 共 21 页该接口通过路由表或者传输ip后,调用netif的output函数指针指向的函数发送报文。【7】udp模块不是我们所关心的,这里就不做介绍【8】icmp 模块用的不多,不必关心【9】igmp

34、模块用的不多,不必关心【10】dhcp模块可能会用到。dhcp模块用于获取设备ip地址的相关信息。其处理入口主要有这么几个:dpch的启动、dpch的接收报文处理以及定时器模块的处理。主要的接口原型如下:err_t dhcp_start(struct netif *netif)该接口用于设备启动dhcp模块,主要是客户端的功能。该模块实现设备dhcp描述结构生成,并将dhcp的端口绑定到udp协议中,以及将本dhcp模块跟远端服务器端口进行绑定。最后启动dhcp申请。static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbu

35、f *p, struct ip_addr *addr, u16_t port)该接口为一个注册接口,用于dhcp报文接收。在start dhcp时,该接口通过dhcp的udp pcb注册到udp协议层。Udp进行报文处理后,根据端口调用该注册接口。该接口中,实现dhcp报文的协议处理。Void dhcp_fine_tmr()Void dhcp_coarse_tmr()这两个函数接口实现了dhcp的相关超时处理监控。上面一个用于请求应答超时处理。下面一个用于地址租用情况的到期处理。从源码分析看,上述的接口在应用lwip的协议栈时,需要重点关注。对于小内存应用的场合,该协议栈的内存管理以及pbuf应用部分需要自行改写16 / 21 第 16 页 共 21 页三、 LWIP协议栈处理数据流程协议栈处理数据的流程主要是处理TCP数据包。关于UDP数据报的处理流程暂且不做讨论。LWIP对TCP数据包的处理流程如下图3.1所示。图3.1LWIP协议栈数据处理流程如上图所示,lwip协议栈对TCP数据包的处理经过四层的处理。分别为应用层,传输层,网络层和网络接口层。图中左半边部分是数据发送的处理部分,右半部分是数据接

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论