zoukankan      html  css  js  c++  java
  • 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 "));
           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" ", 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. ",
                                   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. ",
                                   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. ", 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") ",
              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 ",

                  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" ",
            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. "));
            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. "));
          /* 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. "));
    #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() ",
          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). ",
          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). "));
        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: "));
      ip_debug_print(p);
      LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F" ", 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" ", IPH_PROTO(iphdr)));

          IP_STATS_INC(ip.proterr);
          IP_STATS_INC(ip.drop);
          snmp_inc_ipinunknownprotos();
        }
      }

      return ERR_OK;
    }

    接下来该分析一下udp_input了

  • 相关阅读:
    [Redux-Observable && Unit Testing] Use tests to verify updates to the Redux store (rxjs scheduler)
    [Redux-Observable && Unit Testing] Mocking an ajax request when testing epics
    [Redux-Observable && Unit testing] Testing the output of epics
    [React] Create a queue of Ajax requests with redux-observable and group the results.
    [React] Compound Component (React.Children.map & React.cloneElement)
    [Express] Upload Files with Express
    [Python] List & Object spread in Python
    [Angular & Unit Testing] Testing a RouterOutlet component
    [Angular & Unit Testing] TestBed.get vs Injector
    各司其职的标签
  • 原文地址:https://www.cnblogs.com/alan666/p/8312144.html
Copyright © 2011-2022 走看看