⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 etharp.c

📁 rtlinux-3.2源码
💻 C
📖 第 1 页 / 共 2 页
字号:
 *  * Should be called for incoming ARP packets. The pbuf in the argument * is freed by this function. * * @param netif The lwIP network interface on which the ARP packet pbuf arrived. * @param pbuf The ARP packet that arrived on netif. Is freed by this function. * @param ethaddr Ethernet address of netif. * * @return NULL * * @see pbuf_free() */struct pbuf *etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p){  struct etharp_hdr *hdr;  u8_t i;  /* drop short ARP packets */  if(p->tot_len < sizeof(struct etharp_hdr)) {    DEBUGF(ETHARP_DEBUG | DBG_TRACE | 1, ("etharp_arp_input: packet too short (%d/%d)\n", p->tot_len, sizeof(struct etharp_hdr)));    pbuf_free(p);    return NULL;  }  hdr = p->payload;  switch(htons(hdr->opcode)) {  /* ARP request? */  case ARP_REQUEST:    /* ARP request. If it asked for our address, we send out a    reply. In any case, we time-stamp any existing ARP entry,    and possiby send out an IP packet that was queued on it. */    DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP request\n"));    /* we are not configured? */    if(netif->ip_addr.addr == 0) {      DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: we are unconfigured, ARP request ignored.\n"));      pbuf_free(p);      return NULL;    }    /* update the ARP cache */    update_arp_entry(netif, &(hdr->sipaddr), &(hdr->shwaddr), 0);    /* ARP request for our address? */    if(ip_addr_cmp(&(hdr->dipaddr), &(netif->ip_addr))) {      DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: replying to ARP request for our IP address\n"));      /* re-use pbuf to send ARP reply */      hdr->opcode = htons(ARP_REPLY);      ip_addr_set(&(hdr->dipaddr), &(hdr->sipaddr));      ip_addr_set(&(hdr->sipaddr), &(netif->ip_addr));      for(i = 0; i < netif->hwaddr_len; ++i) {        hdr->dhwaddr.addr[i] = hdr->shwaddr.addr[i];        hdr->shwaddr.addr[i] = ethaddr->addr[i];        hdr->ethhdr.dest.addr[i] = hdr->dhwaddr.addr[i];        hdr->ethhdr.src.addr[i] = ethaddr->addr[i];      }      hdr->hwtype = htons(HWTYPE_ETHERNET);      ARPH_HWLEN_SET(hdr, netif->hwaddr_len);        hdr->proto = htons(ETHTYPE_IP);      ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));              hdr->ethhdr.type = htons(ETHTYPE_ARP);            /* return ARP reply */      netif->linkoutput(netif, p);    } else {      DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP request was not for us.\n"));    }    break;  case ARP_REPLY:        /* ARP reply. We insert or update the ARP table. */    DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n"));#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)    /* DHCP needs to know about ARP replies */    dhcp_arp_reply(netif, &hdr->sipaddr);#endif    /* ARP reply directed to us? */    if(ip_addr_cmp(&(hdr->dipaddr), &(netif->ip_addr))) {      DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP reply is for us\n"));      /* update_the ARP cache, ask to insert */      update_arp_entry(netif, &(hdr->sipaddr), &(hdr->shwaddr), ARP_INSERT_FLAG);    /* ARP reply not directed to us */    } else {      DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP reply is not for us\n"));      /* update the destination address pair */      update_arp_entry(netif, &(hdr->sipaddr), &(hdr->shwaddr), 0);      /* update the destination address pair */      update_arp_entry(netif, &(hdr->dipaddr), &(hdr->dhwaddr), 0);    }    break;  default:    DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %d\n", htons(hdr->opcode)));    break;  }  /* free ARP packet */  pbuf_free(p);  p = NULL;  /* nothing to send, we did it! */  return NULL;}/**  * Resolve and fill-in Ethernet address header for outgoing packet. * * If ARP has the Ethernet address in cache, the given packet is * returned, ready to be sent. * * If ARP does not have the Ethernet address in cache the packet is * queued and a ARP request is sent (on a best-effort basis). This * ARP request is returned as a pbuf, which should be sent by the * caller. * * If ARP failed to allocate resources, NULL is returned. * * A returned non-NULL packet should be sent by the caller and * etharp_output_sent() must be called afterwards to free any ARP * request. * * @param netif The lwIP network interface which the IP packet will be sent on. * @param ipaddr The IP address of the packet destination. * @param pbuf The pbuf(s) containing the IP packet to be sent. *  * @return If non-NULL, a packet ready to be sent.  * @see etharp_output_sent() */struct pbuf *etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q){  struct eth_addr *dest, *srcaddr, mcastaddr;  struct eth_hdr *ethhdr;  u8_t i;  /* Make room for Ethernet header. */  if(pbuf_header(q, sizeof(struct eth_hdr)) != 0) {        /* The pbuf_header() call shouldn't fail, and we'll just bail    out if it does.. */    DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_output: could not allocate room for header.\n"));#ifdef LINK_STATS    ++lwip_stats.link.lenerr;#endif /* LINK_STATS */    return NULL;  }  /* obtain source Ethernet address of the given interface */  srcaddr = (struct eth_addr *)netif->hwaddr;  /* assume unresolved Ethernet address */  dest = NULL;  /* Construct Ethernet header. Start with looking up deciding which  MAC address to use as a destination address. Broadcasts and  multicasts are special, all other addresses are looked up in the  ARP table. */  /* destination IP address is an IP broadcast address? */  if(ip_addr_isany(ipaddr) ||    ip_addr_isbroadcast(ipaddr, &(netif->netmask))) {    /* broadcast on Ethernet also */    dest = (struct eth_addr *)&ethbroadcast;  }  /* destination IP address is an IP multicast address? */  else if(ip_addr_ismulticast(ipaddr)) {    /* Hash IP multicast address to MAC address. */    mcastaddr.addr[0] = 0x01;    mcastaddr.addr[1] = 0x0;    mcastaddr.addr[2] = 0x5e;    mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f;    mcastaddr.addr[4] = ip4_addr3(ipaddr);    mcastaddr.addr[5] = ip4_addr4(ipaddr);    /* destination Ethernet address is multicast */    dest = &mcastaddr;  }  /* destination IP address is an IP unicast address */  else {    /* destination IP network address not on local network? */    /* this occurs if the packet is routed to the default gateway on this interface */    if(!ip_addr_maskcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) {      /* gateway available? */      if (netif->gw.addr != 0)      {        /* use the gateway IP address */        ipaddr = &(netif->gw);      }      /* no gateway available? */      else      {        /* IP destination address outside local network, but no gateway available */        return NULL;      }    }    /* Ethernet address for IP destination address is in ARP cache? */    for(i = 0; i < ARP_TABLE_SIZE; ++i) {      /* match found? */          if(arp_table[i].state == ETHARP_STATE_STABLE &&        ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {        dest = &arp_table[i].ethaddr;        break;      }    }    /* could not find the destination Ethernet address in ARP cache? */    if (dest == NULL) {      /* ARP query for the IP address, submit this IP packet for queueing */      etharp_query(netif, ipaddr, q);      /* return nothing */      return NULL;    }    /* destination Ethernet address resolved from ARP cache */    else    {      /* fallthrough */    }  }  /* destination Ethernet address known */  if (dest != NULL) {    /* A valid IP->MAC address mapping was found, so we construct the    Ethernet header for the outgoing packet. */    ethhdr = q->payload;    for(i = 0; i < netif->hwaddr_len; i++) {      ethhdr->dest.addr[i] = dest->addr[i];      ethhdr->src.addr[i] = srcaddr->addr[i];    }    ethhdr->type = htons(ETHTYPE_IP);    /* return the outgoing packet */    return q;  }  /* never reached; here for safety */   return NULL;}/** * Send an ARP request for the given IP address. * * Sends an ARP request for the given IP address, unless * a request for this address is already pending. Optionally * queues an outgoing packet on the resulting ARP entry. * * @param netif The lwIP network interface where ipaddr * must be queried for. * @param ipaddr The IP address to be resolved. * @param q If non-NULL, a pbuf that must be queued on the * ARP entry for the ipaddr IP address. * * @return NULL. * * @note Might be used in the future by manual IP configuration * as well. * * TODO: enqueue q here if possible (BEWARE: possible other packet already * queued. * TODO: The host requirements RFC states that ARP should save at least one * packet, and this should be the _latest_ packet. * TODO: use the ctime field to see how long ago an ARP request was sent, * possibly retry. */err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q){  struct eth_addr *srcaddr;  struct etharp_hdr *hdr;  struct pbuf *p;  err_t result = ERR_OK;  u8_t i;  u8_t perform_arp_request = 1;  /* prevent warning if ARP_QUEUEING == 0 */  if (q);  srcaddr = (struct eth_addr *)netif->hwaddr;  /* bail out if this IP address is pending */  for(i = 0; i < ARP_TABLE_SIZE; ++i) {    if(ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {      if (arp_table[i].state == ETHARP_STATE_PENDING) {        DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: requested IP already pending as entry %u\n", i));        /* break out of for-loop, user may wish to queue a packet on a stable entry */        break;      }      else if (arp_table[i].state == ETHARP_STATE_STABLE) {        DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: requested IP already stable as entry %u\n", i));        /* user may wish to queue a packet on a stable entry, so we proceed without ARP requesting */        /* TODO: even if the ARP entry is stable, we might do an ARP request anyway in some cases? */        perform_arp_request = 0;        break;      }    }  }  /* queried address not yet in ARP table? */  if (i == ARP_TABLE_SIZE) {    DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: IP address not found in ARP table\n"));    /* find an available entry */    i = find_arp_entry();    /* bail out if no ARP entries are available */    if (i == ARP_TABLE_SIZE) {      DEBUGF(ETHARP_DEBUG | 2, ("etharp_query: no more ARP entries available.\n"));      return ERR_MEM;    }    DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: created ARP table entry %u.\n", i));    /* i is available, create ARP entry */    ip_addr_set(&arp_table[i].ipaddr, ipaddr);    arp_table[i].ctime = 0;    arp_table[i].state = ETHARP_STATE_PENDING;#if ARP_QUEUEING    /* free queued packet, as entry is now invalidated */    if (arp_table[i].p != NULL) {      pbuf_free(arp_table[i].p);      arp_table[i].p = NULL;      DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("etharp_query: dropped packet on ARP queue. Should not occur.\n"));    }#endif  }#if ARP_QUEUEING  /* any pbuf to queue and queue is empty? */  if (q != NULL) {/* yield later packets over older packets? */#if ARP_QUEUE_FIRST == 0    /* earlier queued packet on this entry? */    if (arp_table[i].p != NULL) {      pbuf_free(arp_table[i].p);      arp_table[i].p = NULL;      DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("etharp_query: dropped packet on ARP queue. Should not occur.\n"));    }#endif    /* packet can be queued? */    if (arp_table[i].p == NULL) {      /* copy PBUF_REF referenced payloads to PBUF_RAM */      q = pbuf_take(q);      /* remember pbuf to queue, if any */      arp_table[i].p = q;      /* pbufs are queued, increase the reference count */      pbuf_ref(q);      DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: queued packet %p on ARP entry %u.\n", (void *)q, i));    }  }#endif  /* ARP request? */  if (perform_arp_request)  {    /* allocate a pbuf for the outgoing ARP request packet */    p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM);    /* could allocate pbuf? */    if (p != NULL) {      u8_t j;      DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: sending ARP request.\n"));      hdr = p->payload;      hdr->opcode = htons(ARP_REQUEST);      for(j = 0; j < netif->hwaddr_len; ++j)      {        hdr->dhwaddr.addr[j] = 0x00;        hdr->shwaddr.addr[j] = srcaddr->addr[j];      }      ip_addr_set(&(hdr->dipaddr), ipaddr);      ip_addr_set(&(hdr->sipaddr), &(netif->ip_addr));      hdr->hwtype = htons(HWTYPE_ETHERNET);      ARPH_HWLEN_SET(hdr, netif->hwaddr_len);      hdr->proto = htons(ETHTYPE_IP);      ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));      for(j = 0; j < netif->hwaddr_len; ++j)      {        hdr->ethhdr.dest.addr[j] = 0xff;        hdr->ethhdr.src.addr[j] = srcaddr->addr[j];      }      hdr->ethhdr.type = htons(ETHTYPE_ARP);            /* send ARP query */      result = netif->linkoutput(netif, p);      /* free ARP query packet */      pbuf_free(p);      p = NULL;    } else {      result = ERR_MEM;      DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_query: could not allocate pbuf for ARP request.\n"));    }  }  return result;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -