分享

lwip之地址解析协议ARP

 立志德美 2019-07-17

ARP — address resolution protocol

1、物理地址和网络地址

(1)结构体定义
//MAC address
#define ETHARP_HWADDR_LEN     6
PACK_STRUCT_BEGIN
struct eth_addr {
  PACK_STRUCT_FIELD(u8_t addr[ETHARP_HWADDR_LEN]);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END

//IP address
struct ip_addr {
  u32_t addr;
};

struct ip_addr_packed {
  PACK_STRUCT_FIELD(u32_t addr);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END

typedef struct ip_addr ip_addr_t;
typedef struct ip_addr_packed ip_addr_p_t;
(2)以太网帧和ARP报文格式

frame

PACK_STRUCT_BEGIN
/** Ethernet header */
struct eth_hdr {
  PACK_STRUCT_FIELD(struct eth_addr dest);
  PACK_STRUCT_FIELD(struct eth_addr src);
  PACK_STRUCT_FIELD(u16_t type);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END

ARP

PACK_STRUCT_BEGIN
/** the ARP message, see RFC 826 ("Packet format") */
struct etharp_hdr {
  PACK_STRUCT_FIELD(u16_t hwtype);
  PACK_STRUCT_FIELD(u16_t proto);
  PACK_STRUCT_FIELD(u8_t  hwlen);
  PACK_STRUCT_FIELD(u8_t  protolen);
  PACK_STRUCT_FIELD(u16_t opcode);
  PACK_STRUCT_FIELD(struct eth_addr shwaddr);
  PACK_STRUCT_FIELD(struct ip_addr2 sipaddr);
  PACK_STRUCT_FIELD(struct eth_addr dhwaddr);
  PACK_STRUCT_FIELD(struct ip_addr2 dipaddr);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END

长度宏声明

#define ETH_PAD_SIZE                    0
#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE)
#define SIZEOF_ETHARP_HDR 28
#define SIZEOF_ETHARP_PACKET (SIZEOF_ETH_HDR + SIZEOF_ETHARP_HDR)

2、ARP缓存表

(1)结构体声明
static struct etharp_entry arp_table[ARP_TABLE_SIZE];

struct etharp_entry {
  struct etharp_q_entry *q;    //挂接在该缓存表的数据包缓冲队列

  ip_addr_t ipaddr;
  struct netif *netif;
  struct eth_addr ethaddr;
  u8_t state;         // 缓存表的状态
  u8_t ctime;         //生存时间计数器
};

struct etharp_q_entry {
  struct etharp_q_entry *next;
  struct pbuf *p;
};

enum etharp_state {
  ETHARP_STATE_EMPTY = 0,
  ETHARP_STATE_PENDING,
  ETHARP_STATE_STABLE,
  ETHARP_STATE_STABLE_REREQUESTING
};
(2)ARP缓存表的定时机制

定时更新缓存表项的状态

#define ARP_TMR_INTERVAL 5000
#define ARP_MAXAGE              240
#define ARP_AGE_REREQUEST_USED  (ARP_MAXAGE - 12)
#define ARP_MAXPENDING 2

void etharp_tmr(void)
{
  u8_t i;

  //查阅缓存表中的每一项状态、时间计数器
  for (i = 0; i < ARP_TABLE_SIZE; ++i) {
    u8_t state = arp_table[i].state;
    if (state != ETHARP_STATE_EMPTY) {
      arp_table[i].ctime++;
      if ((arp_table[i].ctime >= ARP_MAXAGE) ||
          ((arp_table[i].state == ETHARP_STATE_PENDING)  &&
           (arp_table[i].ctime >= ARP_MAXPENDING))) {
        etharp_free_entry(i);
      }
      else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING) {
        arp_table[i].state = ETHARP_STATE_STABLE;
      }
    }
  }
}

static void etharp_free_entry(int i)
{
//判断是否有挂接在缓存表项的数据
  if (arp_table[i].q != NULL) {
    free_etharp_q(arp_table[i].q);
    arp_table[i].q = NULL;
  }
  /* recycle entry for re-use */
  arp_table[i].state = ETHARP_STATE_EMPTY;
}

#define free_etharp_q(q) pbuf_free(q)

3、gratuitous ARP

Gratuitous ARP也称为免费ARP,无故ARP。Gratuitous ARP不同于一般的ARP请求,它并非期待得到ip对应的mac地址,而是当主机启动的时候,将发送一个Gratuitous arp请求,即请求自己的ip地址的mac地址,发送MAC和接收MAC相同,主要作用是更新同一网段内其它主机的ARP缓存表。

网口建立时,函数netif_set_up中调用函数etharp_gratuitous。

#define etharp_gratuitous(netif) etharp_request((netif), &(netif)->ip_addr)
const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
const struct eth_addr ethzero = {{0,0,0,0,0,0}};

err_t etharp_request(struct netif *netif, ip_addr_t *ipaddr)
{
  return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &ethbroadcast,
                    (struct eth_addr *)netif->hwaddr, &netif->ip_addr, &ethzero,
                    ipaddr, ARP_REQUEST);
}

/**
 * Send a raw ARP packet (opcode and all addresses can be modified)
 *
 * @param netif the lwip network interface on which to send the ARP packet
 * @param ethsrc_addr the source MAC address for the ethernet header
 * @param ethdst_addr the destination MAC address for the ethernet header
 * @param hwsrc_addr the source MAC address for the ARP protocol header
 * @param ipsrc_addr the source IP address for the ARP protocol header
 * @param hwdst_addr the destination MAC address for the ARP protocol header
 * @param ipdst_addr the destination IP address for the ARP protocol header
 * @param opcode the type of the ARP packet
 * @return ERR_OK if the ARP packet has been sent
 *         ERR_MEM if the ARP packet couldn't be allocated
 *         any other err_t on failure
 */

//创建一个ARP请求包
err_t etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
           const struct eth_addr *ethdst_addr,
           const struct eth_addr *hwsrc_addr, const ip_addr_t *ipsrc_addr,
           const struct eth_addr *hwdst_addr, const ip_addr_t *ipdst_addr,
           const u16_t opcode)
{
  struct pbuf *p;
  err_t result = ERR_OK;
  struct eth_hdr *ethhdr;
  struct etharp_hdr *hdr;

  /* allocate a pbuf for the outgoing ARP request packet */
  p = pbuf_alloc(PBUF_RAW, SIZEOF_ETHARP_PACKET, PBUF_RAM);

  if (p == NULL) {
    return ERR_MEM;
  }

  ethhdr = (struct eth_hdr *)p->payload;
  hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);

//填充以太网帧首部14字节
/* Write the Ethernet MAC-Addresses */
  ETHADDR16_COPY(&ethhdr->dest, ethdst_addr);
  ETHADDR16_COPY(&ethhdr->src, ethsrc_addr);

   ethhdr->type = PP_HTONS(ETHTYPE_ARP); //帧类型

  //填充ARP报文20个字节
  hdr->opcode = htons(opcode);  //操作码:申请或回复,转换为网络字节顺序

  /* Write the ARP MAC-Addresses */
  ETHADDR16_COPY(&hdr->shwaddr, hwsrc_addr);
  ETHADDR16_COPY(&hdr->dhwaddr, hwdst_addr);

  /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
   * structure packing. */ 
  IPADDR2_COPY(&hdr->sipaddr, ipsrc_addr);
  IPADDR2_COPY(&hdr->dipaddr, ipdst_addr);

  hdr->hwtype = PP_HTONS(HWTYPE_ETHERNET);   //硬件类型
  hdr->proto = PP_HTONS(ETHTYPE_IP);     // 协议类型
  /* set hwlen and protolen */
  hdr->hwlen = ETHARP_HWADDR_LEN;    //硬件长度
  hdr->protolen = sizeof(ip_addr_t); // 协议长度

  /* send ARP query */
  result = netif->linkoutput(netif, p);

  /* free ARP query packet */
  pbuf_free(p);
  p = NULL;

  return result;
}

对结构体中双字节以上的成员变量,注意小端和大端字节顺序的区别。
相关宏声明

#define HWTYPE_ETHERNET 1

#define ETHTYPE_ARP       0x0806U
#define ETHTYPE_IP        0x0800U
#define ETHTYPE_VLAN      0x8100U
#define ETHTYPE_PPPOEDISC 0x8863U  /* PPP Over Ethernet Discovery Stage */
#define ETHTYPE_PPPOE     0x8864U  /* PPP Over Ethernet Session Stage */

/** ARP message types (opcodes) */
#define ARP_REQUEST 1
#define ARP_REPLY   2

4、ARP层的数据包输入

函数ethernetif_input封装了网卡数据包的接收,ARP解析主要分为以下几个过程:1、函数low_level_input 实现接收底层网卡数据并转换为pbuf类型的数据包;2、函数ethernet_input 分析接收的数据包是IP报文还是ARP报文;3、若为ARP报文,调用函数etharp_arp_input处理缓存表更新及发送ARP应答报文。

1、ethernet_input

err_t ethernet_input(struct pbuf *p, struct netif *netif)
{
  struct eth_hdr* ethhdr;
  u16_t type;
  s16_t ip_hdr_offset = SIZEOF_ETH_HDR;

  if (p->len <= SIZEOF_ETH_HDR) {
    goto free_and_return;
  }

  ethhdr = (struct eth_hdr *)p->payload;
  type = ethhdr->type;

  if (ethhdr->dest.addr[0] & 1) {
    /* this might be a multicast or broadcast packet */
    if (ethhdr->dest.addr[0] == LL_MULTICAST_ADDR_0) {
      if ((ethhdr->dest.addr[1] == LL_MULTICAST_ADDR_1) &&
          (ethhdr->dest.addr[2] == LL_MULTICAST_ADDR_2)) {
        /* mark the pbuf as link-layer multicast */
        p->flags |= PBUF_FLAG_LLMCAST;
      }
    } else if (eth_addr_cmp(&ethhdr->dest, &ethbroadcast)) {
      /* mark the pbuf as link-layer broadcast */
      p->flags |= PBUF_FLAG_LLBCAST;
    }
  }

  switch (type) {
    /* IP packet? */
    case PP_HTONS(ETHTYPE_IP):    //IP报文
      if (!(netif->flags & NETIF_FLAG_ETHARP)) {
        goto free_and_return;
      }
#if ETHARP_TRUST_IP_MAC
      /* update ARP table */
      etharp_ip_input(netif, p);
#endif /* ETHARP_TRUST_IP_MAC */
      /* skip Ethernet header */
      if(pbuf_header(p, -ip_hdr_offset)) {
        LWIP_ASSERT("Can't move over header in packet", 0);
        goto free_and_return;
      } else {
        /* pass to IP layer */
        ip_input(p, netif);
      }
      break;

    case PP_HTONS(ETHTYPE_ARP):    //arp报文
      if (!(netif->flags & NETIF_FLAG_ETHARP)) {
        goto free_and_return;
      }
      /* pass p to ARP module */
      etharp_arp_input(netif, (struct eth_addr*)(netif->hwaddr), p);
      break;

    default:
      goto free_and_return;
  }

  return ERR_OK;

free_and_return:
  pbuf_free(p);
  return ERR_OK;
}

2、 etharp_arp_input

static void
etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
{
  struct etharp_hdr *hdr;
  struct eth_hdr *ethhdr;
  ip_addr_t sipaddr, dipaddr;
  u8_t for_us;

  if (p->len < SIZEOF_ETHARP_PACKET) {
    pbuf_free(p);
    return;
  }

  ethhdr = (struct eth_hdr *)p->payload;
  hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);

  /* RFC 826 "Packet Reception": */
  if ((hdr->hwtype != PP_HTONS(HWTYPE_ETHERNET)) ||
      (hdr->hwlen != ETHARP_HWADDR_LEN) ||
      (hdr->protolen != sizeof(ip_addr_t)) ||
      (hdr->proto != PP_HTONS(ETHTYPE_IP)))  {
    pbuf_free(p);
    return;
  }

  IPADDR2_COPY(&sipaddr, &hdr->sipaddr);
  IPADDR2_COPY(&dipaddr, &hdr->dipaddr);

  if (ip_addr_isany(&netif->ip_addr)) {
    for_us = 0;
  } else {
    for_us = (u8_t)ip_addr_cmp(&dipaddr, &(netif->ip_addr));
  }

  //更新ARP缓存表
  etharp_update_arp_entry(netif, &sipaddr, &(hdr->shwaddr),
                   for_us ? ETHARP_FLAG_TRY_HARD : ETHARP_FLAG_FIND_ONLY);

  switch (hdr->opcode) {
  case PP_HTONS(ARP_REQUEST):

    if (for_us) {
      hdr->opcode = htons(ARP_REPLY);

      IPADDR2_COPY(&hdr->dipaddr, &hdr->sipaddr);
      IPADDR2_COPY(&hdr->sipaddr, &netif->ip_addr);

      ETHADDR16_COPY(&hdr->dhwaddr, &hdr->shwaddr);
      ETHADDR16_COPY(&ethhdr->dest, &hdr->shwaddr);
      ETHADDR16_COPY(&hdr->shwaddr, ethaddr);
      ETHADDR16_COPY(&ethhdr->src, ethaddr);

      //发送ARP应答包时,只需更新接收的ARP请求包,更改ARP报文中的目的地址和发送地址及操作码,并调用底层网卡发送数据包函数
      /* return ARP reply */
      netif->linkoutput(netif, p);
    /* we are not configured? */
    } else if (ip_addr_isany(&netif->ip_addr)) {
      /* { for_us == 0 and netif->ip_addr.addr == 0 } */

    /* request was not directed to us */
    } else {
      /* { for_us == 0 and netif->ip_addr.addr != 0 } */
    }
    break;
  case PP_HTONS(ARP_REPLY):
    break;
  default:
    break;
  }
  /* free ARP packet */
  pbuf_free(p);
}

3、ARP缓存表查找可利用表项索引并更新ARP缓存表

static s8_t etharp_find_entry(ip_addr_t *ipaddr, u8_t flags)
{
  s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE;
  s8_t empty = ARP_TABLE_SIZE;
  u8_t i = 0, age_pending = 0, age_stable = 0;

  s8_t old_queue = ARP_TABLE_SIZE;
  u8_t age_queue = 0;

  /**
   * a) do a search through the cache, remember candidates
   * b) select candidate entry
   * c) create new entry
   */

  /* a) in a single search sweep, do all of this
   * 1) remember the first empty entry (if any)
   * 2) remember the oldest stable entry (if any)
   * 3) remember the oldest pending entry without queued packets (if any)
   * 4) remember the oldest pending entry with queued packets (if any)
   * 5) search for a matching IP entry, either pending or stable
   *    until 5 matches, or all entries are searched for.
   */

  for (i = 0; i < ARP_TABLE_SIZE; ++i) {
    u8_t state = arp_table[i].state;

    if ((empty == ARP_TABLE_SIZE) && (state == ETHARP_STATE_EMPTY)) {
      empty = i;
    } else if (state != ETHARP_STATE_EMPTY) {
      if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
        return i;
      }

      if (state == ETHARP_STATE_PENDING) {
        if (arp_table[i].q != NULL) {
          if (arp_table[i].ctime >= age_queue) {
            old_queue = i;
            age_queue = arp_table[i].ctime;
          }
        } else
        {
          if (arp_table[i].ctime >= age_pending) {
            old_pending = i;
            age_pending = arp_table[i].ctime;
          }
        }
      } else if (state >= ETHARP_STATE_STABLE) {
        {
          /* remember entry with oldest stable entry in oldest, its age in maxtime */
          if (arp_table[i].ctime >= age_stable) {
            old_stable = i;
            age_stable = arp_table[i].ctime;
          }
        }
      }
    }
  }
  /* { we have no match } => try to create a new entry */

  if (((flags & ETHARP_FLAG_FIND_ONLY) != 0) ||
      ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_FLAG_TRY_HARD) == 0))) {
    return (s8_t)ERR_MEM;
  }

  /* b) choose the least destructive entry to recycle:
   * 1) empty entry
   * 2) oldest stable entry
   * 3) oldest pending entry without queued packets
   * 4) oldest pending entry with queued packets
   * 
   * { ETHARP_FLAG_TRY_HARD is set at this point }
   */ 

  /* 1) empty entry available? */
  if (empty < ARP_TABLE_SIZE) {
    i = empty;
  } else {
    /* 2) found recyclable stable entry? */
    if (old_stable < ARP_TABLE_SIZE) {
      /* recycle oldest stable*/
      i = old_stable;
    /* 3) found recyclable pending entry without queued packets? */
    } else if (old_pending < ARP_TABLE_SIZE) {
      i = old_pending;
    /* 4) found recyclable pending entry with queued packets? */
    } else if (old_queue < ARP_TABLE_SIZE) {
      i = old_queue;
    } else {
      return (s8_t)ERR_MEM;
    }
    etharp_free_entry(i);
  }

  /* IP address given? */
  if (ipaddr != NULL) {
    /* set IP address */
    ip_addr_copy(arp_table[i].ipaddr, *ipaddr);
  }
  arp_table[i].ctime = 0;
  return (err_t)i;
}

static err_t etharp_update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags)
{
  s8_t i;

  if (ip_addr_isany(ipaddr) ||
      ip_addr_isbroadcast(ipaddr, netif) ||
      ip_addr_ismulticast(ipaddr)) {
    return ERR_ARG;
  }

  i = etharp_find_entry(ipaddr, flags);
  if (i < 0) {
    return (err_t)i;
  }

    /* mark it stable */
  arp_table[i].state = ETHARP_STATE_STABLE;
  arp_table[i].netif = netif;

  ETHADDR32_COPY(&arp_table[i].ethaddr, ethaddr);
  arp_table[i].ctime = 0;

  while (arp_table[i].q != NULL) {
    struct pbuf *p;
    struct etharp_q_entry *q = arp_table[i].q;
    arp_table[i].q = q->next;
    p = q->p;
    memp_free(MEMP_ARP_QUEUE, q);
    // 发送挂接的数据包
    etharp_send_ip(netif, p, (struct eth_addr*)(netif->hwaddr), ethaddr);
    pbuf_free(p);
  }
  return ERR_OK;
}

5、数据包输出

(1)etharp_output—IP层调用的数据包发送函数
err_t
etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
{
  struct eth_addr *dest;
  struct eth_addr mcastaddr;
  ip_addr_t *dst_addr = ipaddr;

  /* make room for Ethernet header - should not fail */
  if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
    return ERR_BUF;
  }

//首先确定发送目的地址是广播地址、多播地址还是单播地址,根据IP地址类型填充MAC地址
  if (ip_addr_isbroadcast(ipaddr, netif)) {
    dest = (struct eth_addr *)&ethbroadcast;
  } else if (ip_addr_ismulticast(ipaddr)) {

    mcastaddr.addr[0] = LL_MULTICAST_ADDR_0;
    mcastaddr.addr[1] = LL_MULTICAST_ADDR_1;
    mcastaddr.addr[2] = LL_MULTICAST_ADDR_2;
    mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f;
    mcastaddr.addr[4] = ip4_addr3(ipaddr);
    mcastaddr.addr[5] = ip4_addr4(ipaddr);
    dest = &mcastaddr;

  } else {
    s8_t i;
 //判断发送IP地址与网卡IP地址是否在同一网段内
    if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask)) &&
        !ip_addr_islinklocal(ipaddr)) {
         //检查网关地址的合法性
        if (!ip_addr_isany(&netif->gw)) {
     //若不在同一网络,目的地址改为网关IP地址
          dst_addr = &(netif->gw);

        } else {
          return ERR_RTE;
        }
      }
    }

//查找是否与最近一次ARP查找表项IP地址相同,全局变量etharp_cached_entry
        if ((arp_table[etharp_cached_entry].state >= ETHARP_STATE_STABLE) &&
            (ip_addr_cmp(dst_addr, &arp_table[etharp_cached_entry].ipaddr))) {
          return etharp_output_to_arp_index(netif, q, etharp_cached_entry);
        }

    //此代码段为提高查找效率
    /* find stable entry: do this here since this is a critical path for
       throughput and etharp_find_entry() is kind of slow */
    for (i = 0; i < ARP_TABLE_SIZE; i++) {
      if ((arp_table[i].state >= ETHARP_STATE_STABLE) &&
          (ip_addr_cmp(dst_addr, &arp_table[i].ipaddr))) {
        return etharp_output_to_arp_index(netif, q, i);
      }
    }

    //无对stable ARP缓存表项,直接更新ARP缓存表
    return etharp_query(netif, dst_addr, q);
  }

//多播地址和广播地址直接发送报文
  return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr), dest);
}
(2)etharp_query

该函数的主要用于查找可用缓存表表项,并将发送的数据包挂接在缓存表项的队列上。挂接的pbuf在收到ARP应答包时调用函数etharp_update_arp_entry时发送。

err_t
etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)
{
  struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr;
  err_t result = ERR_MEM;
  s8_t i; /* ARP entry index */

  /* non-unicast address? */
  if (ip_addr_isbroadcast(ipaddr, netif) ||
      ip_addr_ismulticast(ipaddr) ||
      ip_addr_isany(ipaddr)) {
    return ERR_ARG;
  }

  /* find entry in ARP cache, ask to create entry if queueing packet */
  i = etharp_find_entry(ipaddr, ETHARP_FLAG_TRY_HARD);

  /* could not find or create entry? */
  if (i < 0) {
    return (err_t)i;
  }

  /* mark a fresh entry as pending (we just sent a request) */
  if (arp_table[i].state == ETHARP_STATE_EMPTY) {
    arp_table[i].state = ETHARP_STATE_PENDING;
  }


  if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) {
    result = etharp_request(netif, ipaddr);
    if (result != ERR_OK) {
    }
    if (q == NULL) {
      return result;
    }
  }

  /* stable entry? */
  if (arp_table[i].state >= ETHARP_STATE_STABLE) {
    result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr));
  } else if (arp_table[i].state == ETHARP_STATE_PENDING) {
    struct pbuf *p;
    int copy_needed = 0;

    p = q;
    //不能挂接PBUF_ROM型的pbuf
    while (p) {
      if(p->type != PBUF_ROM) {
        copy_needed = 1;
        break;
      }
      p = p->next;
    }
    if(copy_needed) {

      p = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
      if(p != NULL) {
        if (pbuf_copy(p, q) != ERR_OK) {
          pbuf_free(p);
          p = NULL;
        }
      }
    } else {

      p = q;
      pbuf_ref(p);
    }

    if (p != NULL) {
      struct etharp_q_entry *new_entry;
      new_entry = (struct etharp_q_entry *)memp_malloc(MEMP_ARP_QUEUE);
      if (new_entry != NULL) {
        new_entry->next = 0;
        new_entry->p = p;
        if(arp_table[i].q != NULL) {
          struct etharp_q_entry *r;
          r = arp_table[i].q;
          while (r->next != NULL) {
            r = r->next;
          }
          r->next = new_entry;
        } else {
          arp_table[i].q = new_entry;
        }
        result = ERR_OK;
      } else {
        pbuf_free(p);
        result = ERR_MEM;
      }

      arp_table[i].q = p;
      result = ERR_OK;

    } else {
      result = ERR_MEM;
    }
  }
  return result;
}
(3)etharp_send_ip

该函数的作用是填充以太网帧首部14个字节,并调用low_level_output底层网卡发送数据包函数。
注意参数为发送方和接收方的MAC地址

static err_t
etharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst)
{
  struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload;

  ETHADDR32_COPY(&ethhdr->dest, dst);
  ETHADDR16_COPY(&ethhdr->src, src);
  ethhdr->type = PP_HTONS(ETHTYPE_IP);

  /* send the packet */
  return netif->linkoutput(netif, p);
}

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多