2009-5-12
LWIP
之IP
层实现
这一部分的实现都是在
ip.c
文件中【
src\cor\ipv4
】,可以看到在这个文件中主要实现了
3
个函数,
ip_input
;
ip_route
;
ip_output
以及
ip_output_if
。下面分别来介绍它们。
这些函数可以分成两大类:接收和发送。下面就先从发送开始,首先要说的就是
ip_output
函数,这个也是发送过程中最重要的一个,它是被
tcp
层调用的,详细可参见以上章节。
* Simple interface to ip_output_if. It finds the outgoing network
* interface and calls upon ip_output_if to do the actual work.
err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
u8_t ttl, u8_t tos, u8_t proto)
{
struct netif *netif;
if ((netif = ip_route(dest)) == NULL) {
return ERR_RTE;
}
return ip_output_if(p, src, dest, ttl, tos, proto, netif);
}
可以看到该函数的实现就像注释所说的一样,直接调用了
ip_route
和
ip_outputif
两个函数。根据以往的经验,先看下
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;
/** IP address configuration in network byte order */
struct ip_addr ip_addr;
struct ip_addr netmask;
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 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. */
err_t (* output)(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr);
/** This function is called by the ARP module when it wants
* 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 *netif);
#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 information 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 netif, NULL is a valid value */
char* hostname;
#endif /* LWIP_NETIF_HOSTNAME */
/** number of bytes used in hwaddr */
u8_t hwaddr_len;
/** link level hardware address of this interface */
u8_t hwaddr[NETIF_MAX_HWADDR_LEN];
/** maximum transfer unit (in bytes) */
u16_t mtu;
/** flags (see NETIF_FLAG_ above) */
u8_t flags;
/** descriptive abbreviation */
char name[2];
/** 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 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 filter 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 */
};
该结构体实现在【
src\include\lwip\netif.h
】,注意到该结构体成员中有
3
个函数指针变量。好了,这个结构体先做一大体了解。用到的时候再详细讲。
接下来先看下
ip_route
函数的实现:
* Finds the appropriate network interface for a given IP address. It
* searches the list of network interfaces linearly. A match is found
* if the masked IP address of the network interface equals the masked
* IP address given to the function.
struct netif * ip_route(struct ip_addr *dest)
{
struct netif *netif;
/* iterate through netifs */
for(netif = netif_list; netif != NULL; netif = netif->next) {
/* network mask matches? */
if (netif_is_up(netif)) {
if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
/* return netif on which to forward IP packet */
return netif;
}
}
}
if ((netif_default == NULL) || (!netif_is_up(netif_default)))
{
snmp_inc_ipoutnoroutes();
return NULL;
}
/* no matching netif found, use default netif */
return netif_default;
}
可以说这个函数的实现很简单,且作用也很容易看懂,就像其注释所说的一样。不过在这个函数中我们还是发现了一些什么,对了,就是
struct netif *netif_list;
【
src\core\netif.c
】的使用。既然这里都使用了这个网络接口链表,那它是在哪里被初始化的呢?
好了,首先我们发现在
netif_add
函数中有对
netif_list
的调用,
netif_add
是被
do_netifapi_netif_add
函数调用的,而
do_netifapi_netif_add
是在
netifapi_netif_add
中通过
netifapi_msg
被
TCPIP_NETIFAPI
调用的。问题似乎很清楚,只要找到
nnetifapi_netif_add
是被谁调用的就好了,然而,搜遍整个工程也没有发现这个函数的影子,除了一个声明一个实现外。
My god
,又进入死胡同了?
好吧,这里先标识一下,待解【见下面的解释】
我们接着看
ip_output_if
这个函数,具体函数可参考【
src\core\ipv4\ip.c
】。它的函数定义注释如下:
* Sends an IP packet on a network interface. This function constructs
* the IP header and calculates the IP header checksum. If the source
* IP address is NULL, the IP address of the outgoing network
* interface is filled in as source address.
* If the destination IP address is IP_HDRINCL, p is assumed to already
* include an IP header and p->payload points to it instead of the data.
再看最后一句:
return netif->output(netif, p, dest);
嗯,看来这个
netif
还是关键啊,如果估计不错的话,接收的时候也要用到这个结构的。那就看它在什么地方被赋值的吧。又经过一番搜索,看来在目前的代码中是找不到的了。查看
lwip
协议栈的设计与实现,特别是网络接口层的那一节,终于明白了,原来这些是要有设备驱动来参与的:【一下为引用】
当收到一个信息包时,设备驱动程序调用
input
指针指向的函数。网络接口通过
output
指针连接到设备驱动。这个指针指向设备驱动中一个向物理网络发送信息包的函数,当信息包包被发送时由
IP
层调用,这个字段由设备驱动的初始设置函数填充。
嗯,那就这样吧,到这里我们可以说
IP
层的发送流程已经走完了。
接下来就是
ip
层的接收过程了。刚才上面也有提到驱动设备收到包,丢给
netif
的
input
函数,这个
input
函数也是设备驱动层来设置的。无非有两个可能,一个是
ip_input
,另外一个就是
tcpip_input
。因为
tcpip_input
函数的处理是最终调用到了
ip_input
【在
tcpip_thread
中】。按照正常情况下应该是
ip_input
函数的,我们先来看下这个函数。
* This function is called by the network interface device driver when
* an IP packet is received. The function does the basic checks of the
* IP header such as packet size being at least larger than the header
* size etc. If the packet was not destined for us, the packet is
* forwarded (using ip_forward). The IP checksum is always checked.
原型:
err_t ip_input(struct pbuf *p, struct netif *inp)
该函数大致的处理过程是:处理
ip
包头;找到对应的
netif
;检查如果是广播或多播包,则丢掉;如果是
tcp
协议的话就直接调用了
tcp_input
函数处理数据。
到此,
ip
层的东西大致就说完了。最后,由于
tcp
和
ip
层的东西都说完了,所以此时我们顺便看下,
tcpip
的整体实现,这个主要是在
src\api\tcpip.c
文件中实现。我们知道发送过程是由
socket
直接调用的,所以这个文件中不涉及,说白了,这个文件主要是涉及到整个接收过程。这里实现的函数有
tcpip_input
,和
tcpip_thread
以及
tcpip_init
函数。
Tcpip_init
函数很简单就是创建系统线程(
sys_thread_new
)
tcpip_thread
。
Tcpip_thread
函数的注释如下:
* The main lwIP thread. This thread has exclusive access to lwIP core functions
* (unless access to them is not locked). Other threads communicate with this
* thread using message boxes.
它的整个过程就是一直从
mbox
中取出
msg
,对各种
msg
的一个处理过程。
Tcpip_input
函数,是在
tcpip_thread
中被调用的处理设备驱动接收到的信息包,并调用
ip_input
来进一步处理。
整个启动过程:
main---> vlwIPInit()
void vlwIPInit( void )
{
/* Initialize lwIP and its interface layer. */
sys_init();
mem_init();
memp_init();
pbuf_init();
netif_init();
ip_init();
sys_set_state(( signed portCHAR * ) "lwIP", lwipTCP_STACK_SIZE);
tcpip_init( NULL, NULL );
sys_set_default_state();
}
从上面我们知道,tcpip_init创建tcpip_thread
在tcpip_thread的开始有如下代码:
(void)arg;
ip_init();
#if LWIP_UDP
udp_init();
#endif
#if LWIP_TCP
tcp_init();
#endif
#if IP_REASSEMBLY
sys_timeout(1000, ip_timer, NULL);
#endif
if (tcpip_init_done != NULL)
{
tcpip_init_done(tcpip_init_done_arg);
}
下面是tcp_init的实现
Void tcp_init(void)
{
/* Clear globals. */
tcp_listen_pcbs.listen_pcbs = NULL;
tcp_active_pcbs = NULL;
tcp_tw_pcbs = NULL;
tcp_tmp_pcb = NULL;
/* initialize timer */
tcp_ticks = 0;
tcp_timer = 0;
}