全部例程

W55MH32 MACRAW模式实现arp请求

W55MH32

更新于 2026年9月21日

本篇总结

在 W55MH32 上通过 MACRAW 模式发送广播 ARP 请求,将目标 IP 地址解析为 MAC 地址,并解析 ARP Probe/请求/响应三种报文。

🔑 KEIL MDK、UART调试、硬件TOE引擎、ARP、MACRAW

硬件平台:本例程基于 W55MH32L-EVB 开发板运行。

采购推荐:点击前往 WIZnet 官方淘宝店铺 选购 W55MH32L-EVB

本示例演示如何在 W55MH32 芯片上通过 MACRAW 模式实现 ARP 协议,将 IP 地址解析为 MAC 地址。MACRAW 模式允许芯片直接收发以太网帧而无需解析 TCP/IP 协议,用户可操作以太网帧头部和有效负载。例程通过 do_arp() 状态机、arp_request() 组包发送和 arp_reply() 校验解析,完整实现 ARP 地址解析功能。

前置工具准备

开始本例程前,请确认以下工具已安装:

MACRAW 模式与 ARP 协议简介

MACRAW 模式是 W55MH32 TOE 提供的一种底层通信模式,芯片直接收发以太网帧而无需解析 TCP/IP 协议,用户可操作以太网帧头部(目的 MAC、源 MAC、以太类型)和有效负载,但仅 Socket0 支持此模式。ARP(Address Resolution Protocol,地址解析协议)工作于数据链路层,用于通过已知 IP 地址解析对应的 MAC 地址,是局域网通信的重要组成部分。

ARP 仅在同一局域网内工作,具有缓存机制以减少广播,通过请求(Opcode=1)查询、响应(Opcode=2)回复完成地址解析。其工作流程为:发送方构建 ARP 请求并以广播方式发送到局域网,所有主机均收到但仅目标主机(IP 匹配)单播回复 ARP 响应,发送方接收后更新 ARP 缓存表。标准 ARP 报文共 28 字节,由硬件类型、协议类型、地址长度、操作码及收发双方地址等字段构成。

特点说明
局域网内工作ARP 仅在同一局域网内工作,广播请求无法跨越路由器
缓存机制设备将 IP-MAC 对应关系缓存一段时间,减少频繁广播
请求与响应Opcode=1 为请求查询,Opcode=2 为响应回复

W55MH32 的优势

W55MH32 的 TOE 引擎原生支持 MACRAW 模式,用户可直接构建以太网帧并通过 Socket0 收发,无需软件实现完整的以太网驱动。MACRAW 模式绕过 TCP/IP 协议栈,适合实现 ARP 等二层协议。

硬件连接与拓扑

请注意:

测试需要 PC 端和 W55MH32 处于同一局域网,ARP 请求的目标 IP 需为同网段在线设备。

  1. Micro USB 线连接 DEBUG USB 口到 PC(供电 + 调试串口)
  2. 网线连接开发板 RJ45 网口 到路由器 LAN 口
┌─────────────────────────────────┐
│ 路由器(DHCP Server) │
│ 192.168.1.1 │
└────┬──────────────────┬───────────┘
│ │
┌────┴──────┐ ┌────┴──────┐
│ W55MH32 │ │ PC │
│ MACRAW ARP│ │ Wireshark │
│ IP: DHCP │ │ IP: DHCP │
└───────────┘ └───────────┘
↑ ↑
DEBUG USB ──→ WIZ UartTool
网络拓扑:开发板与 PC 在同一局域网内,通过路由器互通

工程结构

工程位于 SDK 内 1.SDK\ModuleDemo\WZTOE\MACRAW\,核心文件如下:

MACRAW ARP/
├── Project/
│   └── Project.uvprojx       ← Keil 工程文件
└── USER/
    ├── main.c                ← 初始化 + 主循环
    ├── arp/
    │   ├── arp.c             ← ARP 状态机核心(do_arp/arp_request/arp_reply)
    │   └── arp.h
    ├── wiz_interface/
    │   ├── wiz_interface.c   ← PHY 检测 / 网络初始化
    │   └── wiz_interface.h
    └── uart/
        ├── bsp_uart.c        ← 调试串口 + printf 重定向
        └── bsp_uart.h

步骤1:主循环调用

文件:USER/main.c。在主循环中调用 do_arp() 函数,传入 Socket 号、网络缓冲区和目标 IP 地址。

while (1)
{
    do_arp(SOCKET_ID, ethernet_buf, dest_ip);
}

主循环不断调用 do_arp(),该函数内部基于 Socket 状态机运行:SOCK_CLOSED 时以 MACRAW 模式打开 Socket,SOCK_MACRAW 时发送 ARP 请求并等待回复。

步骤2:do_arp() 状态机

文件:USER/arp/arp.c。当 Socket 为关闭状态时以 MACRAW 模式打开 Socket;当 Socket 成功打开为 MACRAW 模式后,执行 arp_request() 发送 ARP 请求,然后进入循环等待响应。超过 5 秒未得到响应则 ARP 请求失败。

void do_arp(uint8_t sn, uint8_t *buf, uint8_t *dest_ip)
{
  uint16_t rlen       = 0;
  uint16_t local_port = 5000;
  uint16_t cnt        = 0;

  switch (getSn_SR(sn))
  {
  case SOCK_CLOSED:
      close(sn);
      socket(sn, Sn_MR_MACRAW, local_port, 0x00);
      break;
  case SOCK_MACRAW:
      arp_request(sn, local_port, dest_ip);

      while (1)
      {
          if ((rlen = getSn_RX_RSR(sn)) > 0)
          {
              arp_reply(sn, buf, rlen);
              break;
          }
          if (cnt > 1000)
          {
              printf("Request Time out.\r\n");
              cnt = 0;
              break;
          }
          else
          {
              cnt++;
              delay_ms(5);
          }
      }
      break;
  }
  if (arp_succ_flag)
      while (1);
}

状态机关键:socket(sn, Sn_MR_MACRAW, local_port, 0x00) 以 MACRAW 模式打开 Socket(仅 Socket0 支持)。超时检测通过 cnt 计数超过 1000 次(每次 5ms,约 5 秒)。arp_succ_flag 为 1 时表示 ARP 请求成功。

步骤3:arp_request() 发送 ARP 请求

文件:USER/arp/arp.c。进行 ARP 报文的组包和发送:通过 getSHAR() 获取源 MAC,getSIPR() 获取源 IP,填充各字段后以广播方式发送。

void arp_request(uint8_t sn, uint16_t port, uint8_t *dest_ip)
{
  uint16_t i;
  uint8_t  broadcast_addr[4] = {0xff, 0xff, 0xff, 0xff};

  for (i = 0; i < 6; i++)
  {
      pARPMSG.dst_mac[i] = 0xff; // Broadcast address in an Ethernet frame
      pARPMSG.tgt_mac[i] = 0x00;
      if (i < 4)
      {
          pARPMSG.tgt_ip[i] = dest_ip[i];
      }
  }
  getSHAR(pARPMSG.src_mac);              // Fill in the source MAC address of the link layer
  getSHAR(pARPMSG.sender_mac);           // Fill in the MAC address of the sender in ARP
  getSIPR(pARPMSG.sender_ip);            // Enter the IP address of the sender in ARP
  pARPMSG.msg_type = htons(ARP_TYPE);    // ARP type
  pARPMSG.hw_type  = htons(ETHER_TYPE);  // Ethernet type
  pARPMSG.pro_type = htons(PRO_TYPE);    // IP
  pARPMSG.hw_size  = HW_SIZE;            // 6
  pARPMSG.pro_size = PRO_SIZE;           // 4
  pARPMSG.opcode   = htons(ARP_REQUEST); // request: 0x0001;  reply: 0x0002

  if (sendto(sn, (uint8_t *)&pARPMSG, sizeof(pARPMSG), broadcast_addr, port) != sizeof(pARPMSG))
  {
      printf("Fail to send arp request packet.\r\n");
  }
  else
  {
      if (pARPMSG.opcode == htons(ARP_REQUEST))
      {
          printf("Who has %d.%d.%d.%d ?  Tell %d.%d.%d.%d\r\n",
                  pARPMSG.tgt_ip[0], pARPMSG.tgt_ip[1], pARPMSG.tgt_ip[2], pARPMSG.tgt_ip[3],
                  pARPMSG.sender_ip[0], pARPMSG.sender_ip[1], pARPMSG.sender_ip[2], pARPMSG.sender_ip[3]);
      }
      else
      {
          printf("Opcode has wrong value. check opcode!\r\n");
      }
  }
}

报文组包关键:目的 MAC 设为广播地址 FF:FF:FF:FF:FF:FF,目标 MAC 设为 0x00(待解析),Opcode 设为 ARP_REQUEST(0x0001)。htons() 用于字节序转换。通过 sendto() 以广播方式发送。

步骤4:arp_reply() 解析 ARP 响应

文件:USER/arp/arp.c。接收 ARP 报文并进行校验:如果报文为回复报文(Opcode=2)且回复的 IP 地址与请求的 IP 匹配,则将 arp_succ_flag 置 1,表示 ARP 请求成功。

void arp_reply(uint8_t sn, uint8_t *buff, uint16_t rlen)
{
    uint8_t  destip[4];
    uint16_t destport;
    uint8_t  ret_arp_reply[128];
    uint8_t  i;

    recvfrom(sn, (uint8_t *)buff, rlen, destip, &destport);

    if (buff[12] == ARP_TYPE_HI && buff[13] == ARP_TYPE_LO)
    {
        aAPRMSG = (ARPMSG *)buff;
        if ((aAPRMSG->opcode) == htons(ARP_REPLY))
        {
            for (i = 0; i < 4; i++)
            {
                if (aAPRMSG->tgt_ip[i] != pARPMSG.tgt_ip[i])
                {
                    break;
                }
                arp_succ_flag = 1;
            }
            memset(ret_arp_reply, 0x00, 128);
            sprintf((char *)ret_arp_reply, "%d.%d.%d.%d is at %.2x.%.2x.%.2x.%.2x.%.2x.%.2x\r\n",
                    aAPRMSG->sender_ip[0], aAPRMSG->sender_ip[1], aAPRMSG->sender_ip[2], aAPRMSG->sender_ip[3],
                    aAPRMSG->sender_mac[0], aAPRMSG->sender_mac[1], aAPRMSG->sender_mac[2], aAPRMSG->sender_mac[3],
                    aAPRMSG->sender_mac[4], aAPRMSG->sender_mac[5]);

            printf("%d.%d.%d.%d is at %.2x.%.2x.%.2x.%.2x.%.2x.%.2x\r\n",
                    aAPRMSG->sender_ip[0], aAPRMSG->sender_ip[1], aAPRMSG->sender_ip[2], aAPRMSG->sender_ip[3],
                    aAPRMSG->sender_mac[0], aAPRMSG->sender_mac[1], aAPRMSG->sender_mac[2], aAPRMSG->sender_mac[3],
                    aAPRMSG->sender_mac[4], aAPRMSG->sender_mac[5]);
        }
        else if ((aAPRMSG->opcode) == htons(ARP_REQUEST))
        {
            printf("Who has %d.%d.%d.%d ? Tell %.2x.%.2x.%.2x.%.2x.%.2x.%.2x\r\n",
                    aAPRMSG->tgt_ip[0], aAPRMSG->tgt_ip[1], aAPRMSG->tgt_ip[2], aAPRMSG->tgt_ip[3],
                    aAPRMSG->sender_mac[0], aAPRMSG->sender_mac[1], aAPRMSG->sender_mac[2], aAPRMSG->sender_mac[3],
                    aAPRMSG->sender_mac[4], aAPRMSG->sender_mac[5]);
        }
    }
    else
    {
        // printf("This message is not ARP reply: opcode is not 0x02!\r\n");
    }
}

解析关键:先通过 buff[12]/buff[13] 判断帧类型是否为 ARP(0x0806),再通过 Opcode 判断是回复还是请求。回复报文需校验目标 IP 是否匹配,匹配则设置 arp_succ_flag = 1。

注意事项

  • MACRAW 模式仅 Socket0 支持,其他 Socket 无法使用
  • ARP 请求以广播方式发送,目标设备收到后单播回复
  • ARP 报文总长 28 字节,加上以太网帧头 14 字节共 42 字节
  • ARP 仅在同一局域网内工作,无法跨越路由器

运行验证

烧录例程运行后,首先进行 PHY 链路检测,然后打印设置的网络地址信息,接着执行 ARP 请求并打印请求结果。打开 WIZ UartTool V1.0,连接 DEBUG USB 对应 COM 口(115200 / 8N1),串口输出将显示 "Who has x.x.x.x ? Tell x.x.x.x" 的请求信息,以及收到响应后的 "x.x.x.x is at xx:xx:xx:xx:xx:xx" 解析结果。

W55MH32 串口输出 — MACRAW ARP 请求(PHY 链路 + DHCP + ARP 请求/回复)

常见问题

Q: 哪些 Socket 支持 MACRAW 模式

W55MH32 的 TOE 引擎中,仅 Socket0 能设置为 MACRAW 模式。其他 Socket 不支持此模式。MACRAW 模式下芯片直接收发以太网帧,绕过 TCP/IP 协议栈,适合实现 ARP 等二层协议。

Q: ARP 请求为什么使用广播方式发送

因为在发送 ARP 请求时,发送方还不知道目标设备的 MAC 地址,无法构造单播以太网帧。因此必须使用广播地址(FF:FF:FF:FF:FF:FF)发送请求,局域网内所有设备都会收到该广播帧,但只有 IP 地址匹配的目标设备才会回复 ARP 响应。

Q: 如何判断 ARP 请求是否成功

在 arp_reply() 函数中,程序会校验接收到的报文是否为 ARP 响应(Opcode=2),并检查响应中的目标 IP 地址是否与请求的目标 IP 一致。如果匹配,则将 arp_succ_flag 标志位置1,表示 ARP 请求成功。若超过5秒(cnt>1000,每次延时5ms)未收到响应,则打印超时信息。

Q: ARP 报文的总长度是多少

标准的 ARP 报文总长度为 28 字节(不包含以太网帧头)。加上 14 字节的以太网帧头(目的MAC 6字节 + 源MAC 6字节 + 帧类型 2字节),完整的 ARP 以太网帧为 42 字节。

Q: ARP Probe 和普通 ARP 请求有什么区别

ARP Probe 用于检测目标 IP 地址是否已被占用(冲突检测),其发送方 IP 地址为 0.0.0.0(未分配)。普通 ARP 请求的发送方 IP 地址为已分配的真实 IP 地址。两者操作码均为1(request),区别在于发送方 IP 字段的填充方式。

总结

本文基于 W55MH32 的 MACRAW 模式实现了 ARP 地址解析功能:

  • MACRAW 模式:直接操作以太网帧,绕过 TCP/IP 协议栈,仅 Socket0 支持
  • ARP 协议:工作于数据链路层,通过广播请求+单播响应解析 IP 到 MAC 地址
  • 报文格式:28 字节 ARP 报文,包含硬件/协议类型、地址长度、操作码、收发双方地址
  • 实现流程:do_arp 状态机 → arp_request 组包广播 → arp_reply 校验解析
  • 成功判断:arp_succ_flag 置 1 表示请求成功,超时 5 秒表示失败

下载本章例程

我们提供完整的工程文件以及配套开发板,方便你随时测试,快速完成产品开发:

开发环境: Keil MDK5 配套开发板

Andy

W5500 技术支持专家