lwip 分析一
一、接收端
1、通过ehternetif_input
void ethernetif_input(struct netif *netif)
{
struct ethernetif *ethernetif;
struct eth_hdr *ethhdr;
struct pbuf *p;
ethernetif = netif->state;
/* move received packet into a new pbuf */
p = low_level_input(netif); //接收数据
/* no packet could be read, silently ignore this */
if (p == NULL) return;
/* points to packet payload, which starts with an Ethernet header */
ethhdr = p->payload;
switch (htons(ethhdr->type)) {
/* IP or ARP packet? */
case ETHTYPE_IP:
case ETHTYPE_ARP:
#if PPPOE_SUPPORT
/* PPPoE packet? */
case ETHTYPE_PPPOEDISC:
case ETHTYPE_PPPOE:
#endif /* PPPOE_SUPPORT */
/* full packet send to tcpip_thread to process */
if (netif->input(p, netif)!=ERR_OK) //调用etharp.c里的ethnet_input函数
{ LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
pbuf_free(p);
p = NULL;
}
break;
default:
pbuf_free(p);
p = NULL;
break;
}
}
接下来看ethernet_input函数
err_t
ethernet_input(struct pbuf *p, struct netif *netif) //注意这里传递进来的netif以后会根据这个判断是不是我这个网卡的数据
{
struct eth_hdr* ethhdr;
/* points to packet payload, which starts with an Ethernet header */
ethhdr = p->payload;
switch (htons(ethhdr->type)) { //不同协议调用不同函数 arp 0x0806 IP 0x0800
/* IP packet? */
case ETHTYPE_IP:
#if ETHARP_TRUST_IP_MAC //如果使能了arp更新缓冲功能
/* update ARP table */
etharp_ip_input(netif, p); //更新arp列表
#endif /* ETHARP_TRUST_IP_MAC */
/* skip Ethernet header */
if(pbuf_header(p, -(s16_t)sizeof(struct eth_hdr))) {
LWIP_ASSERT("Can't move over header in packet", 0);
pbuf_free(p);
p = NULL;
} else {
/* pass to IP layer */
ip_input(p, netif); //ip协议,调用IP处理函数
}
break;
case ETHTYPE_ARP:
/* pass p to ARP module */
etharp_arp_input(netif, (struct eth_addr*)(netif->hwaddr), p); //arp协议,调用arp处理函数
break;
#if PPPOE_SUPPORT
case ETHTYPE_PPPOEDISC: /* PPP Over Ethernet Discovery Stage */
pppoe_disc_input(netif, p);
break;
case ETHTYPE_PPPOE: /* PPP Over Ethernet Session Stage */
pppoe_data_input(netif, p);
break;
#endif /* PPPOE_SUPPORT */
default:
pbuf_free(p);
p = NULL;
break;
}
/* This means the pbuf is freed or consumed,
so the caller doesn't have to free it again */
return ERR_OK;
}
接下来看 ip_input();
err_t
ip_input(struct pbuf *p, struct netif *inp)
{
struct ip_hdr *iphdr;
struct netif *netif;
u16_t iphdr_hlen;
u16_t iphdr_len;
#if LWIP_DHCP
int check_ip_src=1;
#endif /* LWIP_DHCP */
IP_STATS_INC(ip.recv);
snmp_inc_ipinreceives();
/* identify the IP header */
iphdr = p->payload; //获取数据
if (IPH_V(iphdr) != 4) {
LWIP_DEBUGF(IP_DEBUG | 1, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr)));
ip_debug_print(p);
pbuf_free(p);
IP_STATS_INC(ip.err);
IP_STATS_INC(ip.drop);
snmp_inc_ipinhdrerrors();
return ERR_OK;
}
/* obtain IP header length in number of 32-bit words */
iphdr_hlen = IPH_HL(iphdr);
/* calculate IP header length in bytes */
iphdr_hlen *= 4;
/* obtain ip length in bytes */
iphdr_len = ntohs(IPH_LEN(iphdr));
/* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) { //判断获取的数据是否正确IP报头,数据大小
if (iphdr_hlen > p->len)
LWIP_DEBUGF(IP_DEBUG | 2, ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",
iphdr_hlen, p->len));
if (iphdr_len > p->tot_len)
LWIP_DEBUGF(IP_DEBUG | 2, ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), "
"IP packet dropped.\n",
iphdr_len, p->tot_len));
/* free (drop) packet pbufs */
pbuf_free(p);
IP_STATS_INC(ip.lenerr);
IP_STATS_INC(ip.drop);
snmp_inc_ipindiscards();
return ERR_OK;
}
/* verify checksum */
#if CHECKSUM_CHECK_IP //如果使能了IP校验和
if (inet_chksum(iphdr, iphdr_hlen) != 0) {
LWIP_DEBUGF(IP_DEBUG | 2, ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen)));
ip_debug_print(p);
pbuf_free(p);
IP_STATS_INC(ip.chkerr);
IP_STATS_INC(ip.drop);
snmp_inc_ipinhdrerrors();
return ERR_OK;
}
#endif
/* Trim pbuf. This should have been done at the netif layer,
* but we'll do it anyway just to be sure that its done. */
pbuf_realloc(p, iphdr_len);
/* match packet against an interface, i.e. is this packet for us? */
#if LWIP_IGMP
if (ip_addr_ismulticast(&(iphdr->dest))) {
if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, &(iphdr->dest)))) {
netif = inp;
} else {
netif = NULL;
}
} else
#endif /* LWIP_IGMP */
{
/* start trying with inp. if that's not acceptable, start walking the
list of configured netifs.
'first' is used as a boolean to mark whether we started walking the list */
int first = 1;
netif = inp;
do { //在netif链上寻找合适的网络接口
LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n",
iphdr->dest.addr, netif->ip_addr.addr,
iphdr->dest.addr & netif->netmask.addr,
netif->ip_addr.addr & netif->netmask.addr,
iphdr->dest.addr & ~(netif->netmask.addr)));
/* interface is up and configured? */
if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) { //这里判断接口是否是up状态,
/* unicast to this interface address? */
if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) ||
/* or broadcast on this interface network address? */
ip_addr_isbroadcast(&(iphdr->dest), netif)) { //这里判断是否是目标地址,如果是,就跳出while
LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",
netif->name[0], netif->name[1]));
/* break out of for loop */
break;
}
}
if (first) {
first = 0;
netif = netif_list;
} else {
netif = netif->next;
}
if (netif == inp) {
netif = netif->next;
}
} while(netif != NULL);
}
#if LWIP_DHCP
/* Pass DHCP messages regardless of destination address. DHCP traffic is addressed
* using link layer addressing (such as Ethernet MAC) so we must not filter on IP.
* According to RFC 1542 section 3.1.1, referred by RFC 2131).
*/
if (netif == NULL) {
/* remote port is DHCP server? */
if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",
ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest)));
if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest) == DHCP_CLIENT_PORT) {
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: DHCP packet accepted.\n"));
netif = inp;
check_ip_src = 0;
}
}
}
#endif /* LWIP_DHCP */
/* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */
#if LWIP_DHCP
if (check_ip_src)
#endif /* LWIP_DHCP */
{ if ((ip_addr_isbroadcast(&(iphdr->src), inp)) ||
(ip_addr_ismulticast(&(iphdr->src)))) { //判断是否是广播或多播,如果是,丢弃
/* packet source is not valid */
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: packet source is not valid.\n"));
/* free (drop) packet pbufs */
pbuf_free(p);
IP_STATS_INC(ip.drop);
snmp_inc_ipinaddrerrors();
snmp_inc_ipindiscards();
return ERR_OK;
}
}
/* packet not for us? */
if (netif == NULL) {
/* packet not for us, route or discard */
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: packet not for us.\n"));
#if IP_FORWARD //如果只有一个网络接口卡,这里为0
/* non-broadcast packet? */
if (!ip_addr_isbroadcast(&(iphdr->dest), inp)) {
/* try to forward IP packet on (other) interfaces */
ip_forward(p, iphdr, inp);
} else
#endif /* IP_FORWARD */
{
snmp_inc_ipinaddrerrors();
snmp_inc_ipindiscards();
}
pbuf_free(p);
return ERR_OK;
}
/* packet consists of multiple fragments? */
if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) {
#if IP_REASSEMBLY /* packet fragment reassembly code present? */
LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip_reass()\n",
ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & htons(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8));
/* reassemble the packet*/
p = ip_reass(p);
/* packet not fully reassembled yet? */
if (p == NULL) {
return ERR_OK;
}
iphdr = p->payload;
#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */
pbuf_free(p);
LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",
ntohs(IPH_OFFSET(iphdr))));
IP_STATS_INC(ip.opterr);
IP_STATS_INC(ip.drop);
/* unsupported protocol feature */
snmp_inc_ipinunknownprotos();
return ERR_OK;
#endif /* IP_REASSEMBLY */
}
#if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */
#if LWIP_IGMP
/* there is an extra "router alert" option in IGMP messages which we allow for but do not police */
if((iphdr_hlen > IP_HLEN && (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) {
#else
if (iphdr_hlen > IP_HLEN) {
#endif /* LWIP_IGMP */
LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n"));
pbuf_free(p);
IP_STATS_INC(ip.opterr);
IP_STATS_INC(ip.drop);
/* unsupported protocol feature */
snmp_inc_ipinunknownprotos();
return ERR_OK;
}
#endif /* IP_OPTIONS_ALLOWED == 0 */
/* send to upper layers */
LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n"));
ip_debug_print(p);
LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));
#if LWIP_RAW
/* raw input did not eat the packet? */
if (raw_input(p, inp) == 0)
#endif /* LWIP_RAW */
{
switch (IPH_PROTO(iphdr)) { //判断传输层用什么协议
#if LWIP_UDP
case IP_PROTO_UDP:
#if LWIP_UDPLITE
case IP_PROTO_UDPLITE:
#endif /* LWIP_UDPLITE */
snmp_inc_ipindelivers();
udp_input(p, inp); //UDP协议,调用UDP处理函数
break;
#endif /* LWIP_UDP */
#if LWIP_TCP
case IP_PROTO_TCP:
snmp_inc_ipindelivers();
tcp_input(p, inp); //TCP协议,调用TCP处理函数
break;
#endif /* LWIP_TCP */
#if LWIP_ICMP
case IP_PROTO_ICMP:
snmp_inc_ipindelivers();
icmp_input(p, inp); //ICMP协议,调用ICMP处理函数
break;
#endif /* LWIP_ICMP */
#if LWIP_IGMP
case IP_PROTO_IGMP:
igmp_input(p,inp,&(iphdr->dest));
break;
#endif /* LWIP_IGMP */
default:
#if LWIP_ICMP
/* send ICMP destination protocol unreachable unless is was a broadcast */
if (!ip_addr_isbroadcast(&(iphdr->dest), inp) &&
!ip_addr_ismulticast(&(iphdr->dest))) {
p->payload = iphdr;
icmp_dest_unreach(p, ICMP_DUR_PROTO); //发送ICMP报文,通知主机,有问题
ICMP_DUR_NET = 0, /* net unreachable */
ICMP_DUR_HOST = 1, /* host unreachable */
ICMP_DUR_PROTO = 2, /* protocol unreachable */
ICMP_DUR_PORT = 3, /* port unreachable */
ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */
ICMP_DUR_SR = 5 /* source route failed */
}
#endif /* LWIP_ICMP */
pbuf_free(p);
LWIP_DEBUGF(IP_DEBUG | 2, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));
IP_STATS_INC(ip.proterr);
IP_STATS_INC(ip.drop);
snmp_inc_ipinunknownprotos();
}
}
return ERR_OK;
}
接下来该分析一下udp_input了