lwip的架构分析(基于LPC17xx)

终于开始这部分的工作,计划了很久,但一直都没有实施。以前一直只使用TCP/IP但对其处理的流程确一知半解。计划拿出几天的时间好好的学习下,理解其运行的基本原理。

       一个嵌入式的网络架构一般都由3部分构成:1、应用层。2、协议层。3、网卡层驱动。为了较好的理解lwip的架构。我们从应用层开始一层一层的剥开整个过程,了解整个系统时怎样串联起来的,

       首先是应用层,这里会初始化网络参数。参见下面用户初始化网络的代码:

tcpip_init(tcpip_init_done_signal,(void *) &tcpipdone);     

IP4_ADDR(&gw, 10, 1, 10, 1);

       IP4_ADDR(&ipaddr,10, 1, 10, 234);

       IP4_ADDR(&netmask,255, 255, 255, 0);

       /* Add netif interfacefor lpc17xx_8x */

       if(!netif_add(&lpc_netif, &ipaddr, &netmask, &gw, NULL,lpc_enetif_init,

                               tcpip_input)) {

              LWIP_ASSERT("Netinterface failed to initialize\r\n", 0);

       }

       netif_set_default(&lpc_netif);

       netif_set_up(&lpc_netif);

这是初始化网络代码的一部分。其中最重要的是tcpip_init()和net_add()函数。

串联其中的就是lpc_netif变量,它是一个struct netif结构体,一般一个网卡对应一个struct netif结构,并用一个list将所有网卡链接起来构成一个链表。首先先看看这个接口的定义:

struct netif {

  struct netif *next; /** pointer to next in linked list;指向下一个网卡 */

  ip_addr_t ip_addr;/**网卡的配置参数**/

  ip_addr_t netmask;

  ip_addr_t gw;

  /** This function iscalled by the network device driver

   *  to pass a packet up the TCP/IP stack. */

  netif_input_fn input;//这是个函数指针,由设备驱动程序调用,传递一个网络数据包到TCP/IP层。

  /** This functionis called by the IP module when it wants

   *  to send a packet on the interface. Thisfunction typically

   *  first resolves the hardware address, thensends the packet. */

  netif_output_fn output; //这也是一个函数指针,由IP模块调用发送一个网卡。

  /** This function is called by the ARP modulewhen it wants

   *  to send a packet on the interface. Thisfunction outputs

   *  the pbuf as-is on the link medium. */

  netif_linkoutput_fn linkoutput;//这个函数由ARP协议调用

};

       在tcpip_init()中会有一个重要的调用既创建了tcpip_thread()的线程。 我们来看看这个函数到底做了些什么呢?

void   tcpip_init(tcpip_init_done_fninitfunc, void *arg)

{

  lwip_init();

  if(sys_mbox_new(&mbox,TCPIP_MBOX_SIZE) != ERR_OK) {

    LWIP_ASSERT("failedto create tcpip_thread mbox", 0);

  }

#if LWIP_TCPIP_CORE_LOCKING

 if(sys_mutex_new(&lock_tcpip_core) != ERR_OK) {

    LWIP_ASSERT("failed to createlock_tcpip_core", 0);

  }

#endif /* LWIP_TCPIP_CORE_LOCKING */

 

 sys_thread_new(TCPIP_THREAD_NAME ,tcpip_thread,NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);

}

我从中可以看到调用了3个函数:

1、lwip_init();初始化了lwip需要要用到的一些参数。

2、sys_mutex_new()创建了一个新的互斥锁。

3 sys_thread_new()新建了一个线程处理tcpip协议栈。在这个线程中你会看到线程会阻塞在读mbox的函数上,直到网卡接收到数据才会继续执行下去。详细的代码请参看tcpip.c文件。


下面我们在来看看另一函数net_add(),我们先看它的第六个参数:lpc_enetif_init(),这个参数是一个函数指针,它是lpc mac层的驱动程序中的一个函数。我们在来看看这个函数中到底干了些什么。

{

       err= low_level_init(netif);//初始化MAC以及Phy芯片

       netif->output= lpc_etharp_output;//设置网卡arp输出函数到网卡接口

       netif->linkoutput= lpc_low_level_output;//设置网卡IP数据输出函数网卡接口

sys_thread_new("receive_thread",vPacketReceiveTask, netif->state,

                               DEFAULT_THREAD_STACKSIZE,tskRECPKT_PRIORITY);

                            //底层的接收线程

sys_thread_new("txclean_thread",vTransmitCleanupTask, netif->state,

                               DEFAULT_THREAD_STACKSIZE,tskTXCLEAN_PRIORITY);

                            //底层的发送线程

}

我们再看看接收线程:

首先线程信号量:/* Wait for receive task to wakeup*/

sys_arch_sem_wait(&lpc_netifdata->RxSem,0);

然后读取网卡数据:

lpc_enetif_input(lpc_netifdata->netif);  à pbuf * p=lpc_low_level_input(netif);//读一个包到pbuf包中  à  netif->input(p, netif)//将数据传递给注册的input函数(即tcpip_input()函数)。

 

看完上面的,我们在看看我们在netif_add注册的tcpip_input()

lpc_netif.input=tcpip_input() 及网卡收到网络数据包调用该input函数指针。tcpip_input()函数会根据协议调用sys_mbox_trypost(&mbox, msg)邮箱发送函数,这个函数会将接收到的pbuf数据发给TCP/IP协议栈的处理进程处理(即阻塞的tcpip_thread进程);

 

看到这儿,我都感觉有点凌乱了。在重新的串一下整个流程:首先在主函数中,调用了tcpip_init()函数建立了tcpip的协议栈线程。接着又调用了net_add()函数,特别需要注意的是其两个传入的函数指针(这两个函数是在网卡驱动中实现的(在这里驱动与tcpip栈建立了联系)init参数和input参数。init()函数会调用网卡驱动的初始化函数err_t lpc_enetif_init(struct netif *netif)。在这个函数会新建两个线程,一个是网卡的接收线程(从网卡中读取一个数据包,并调用我们在netif中注册的input函数将数据包交给tcpip协议栈线程处理了),一个是网卡的发送线程(它会阻塞在一个信号量上,当有数据需要发送时,将数据发送出去)。讲到这里应该大概明白了lwip的驱动基本架构了吧!。

你可能感兴趣的:(NetWork,以太网,Lwip)