一、接收端

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了

lwip 分析一的更多相关文章

  1. LWIP互联网资料汇总

    本文主要搜集了下互联网上关于LWIP的资料和教程 欢迎补充 第一部分:移植 LWIP在UCOS上移植 LWIP 在STM32上移植   http://www.docin.com/p-459242028 ...

  2. LwIP协议栈开发嵌入式网络的三种方法分析

    LwIP协议栈开发嵌入式网络的三种方法分析   摘要  轻量级的TCP/IP协议栈LwIP,提供了三种应用程序设计方法,且很容易被移植到多任务的操作系统中.本文结合μC/OS-II这一实时操作系统,以 ...

  3. lwip【5】 lwIP配置文件opt.h和lwipopts.h初步分析之二

    如何去配置lwip,使它去适合不同大小的脚,这就是本贴的主题lwIP的配置问题.尤其是内存的配置,配置多了浪费,配置少了跑不了或者不稳定(会出现的一大堆莫名奇妙的问题,什么打开网页的速度很慢啊?什么丢 ...

  4. lwip【4】 lwIP配置文件opt.h和lwipopts.h初步分析之一

    在这里先说一下这两个配置lwip协议栈文件opt.h和lwipopts.h的关系:          opt.h是lwip"出厂"时原装的配置文件,它的作者是瑞士科学院的Adam等 ...

  5. 【lwip】06-网络接口层分析

    目录 前言 6.1 概念引入 6.2 网络接口层数据概念流图 6.3 网卡收包程序流图 6.4 网卡数据结构 6.4.1 struct netif源码 6.4.2 字段分析 6.4.2.1 网卡链表 ...

  6. 【lwip】07-链路层收发以太网数据帧源码分析

    目录 前言 7.1 链路层概述 7.2 MAC地址的基本概念 7.3 以太网帧结构 7.4 以太网帧结构 7.5 以太网帧报文数据结构 7.6 发送以太网数据帧 7.7 接收以太网数据帧 7.8 虚拟 ...

  7. 【lwip】09-IPv4协议&超全源码实现分析

    目录 前言 9.1 IP协议简述 9.2 IP地址分类 9.2.1 私有地址 9.2.2 受限广播地址 9.2.3 直接广播地址 9.2.4 多播地址 9.2.5 环回地址 9.2.6 本地链路地址 ...

  8. 【lwip】11-UDP协议&源码分析

    目录 前言 11.1 传输层说明 11.2 UDP协议简介 11.3 UDP特点 11.4 UDP端口号 11.5 UDP报文 11.6 UDP伪首部和校验和 11.7 wireshark报文分析 1 ...

  9. 【lwip】10-ICMP协议&源码分析

    目录 前言 10.1 ICMP简介 10.2 ICMP报文 10.2.1 ICMP报文格式 10.2.2 ICMP报文类型 10.2.3 ICMP报文固定首部字段意义 10.3 ICMP差错报告报文 ...

随机推荐

  1. linux查看磁盘挂载的三种方法

    第一种方法:使用df命令,例如: orientalson:/home # df Filesystem 1K-blocks Used Available Use% Mounted on /dev/sda ...

  2. [python学习] 简单爬取图片站点图库中图片

    近期老师让学习Python与维基百科相关的知识,无聊之中用Python简单做了个爬取"游讯网图库"中的图片,由于每次点击下一张感觉很浪费时间又繁琐.主要分享的是怎样爬取HTML的知 ...

  3. python 基础 1.5 python数据类型(三)--元组常用方法示例

    #/usr/bin/python#coding=utf-8#@Time :2017/10/13 15:02#@Auther :liuzhenchuan#@File :元组.py #tuple() 字符 ...

  4. Unix环境高级编程—进程控制(二)

    一.函数wait和waitpid 今天我们继续通过昨天那个死爹死儿子的故事来讲(便于记忆),现在看看wait和waitpid函数. #include<sys/wait.h> pid_t w ...

  5. 关于EasyRTSPClient、EasyPlayer RTSP流重连问题的解释

    EasyPlayer.EasyRTSPClient是如何设计重连的 首先大概解释一下EasyRTSPClient与EasyPlayer间的关系:EasyRTSPClient是一个专门用于与RTSP流媒 ...

  6. Java 8 default 函数

    我们知道在java8之前 ,一个类实现一个接口需要实现接口所有的方法, 但是这样会导致一个问题,当一个接口有很多的实现类的时候,修改这个接口就变成了一个非常麻烦的事,需要修改这个接口的所有实现类 不过 ...

  7. eclipse中 svn出现 E220000 解决办法

    这种情况,先试试修改svnserve.conf 中的 anon-access = none 然后重启eclipse   如果还是不行,还有可能是因为你修改了svn的配置链接后 跟他人的svn连接方式有 ...

  8. cocos2d-x中对象的位置,旋转,缩放

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/cuit/article/details/26729633 分为两种: 缓动.IntervalActi ...

  9. python_learn1

    1.python在命令行获取当前的路径. import os os.getcwd() os.chdir(r"C:\Users\szlon\Desktop\pythonexer") ...

  10. 多线程(三) iOS中的锁

    锁的类别:互斥锁,递归锁,条件锁,自旋锁等 锁的实现方式:NSLock,NSRecursiveLock, NSConditionLock,@synchronized,GCD的信号量等 下面说一下常用的 ...