首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

STM32NET学习笔记 ARP和Ethernet部分(2)

STM32NET学习笔记 ARP和Ethernet部分(2)

4.实现ARP    为了使用最少的代码实现TCPIP功能,假设通过IP发送报文时已经确认了目标的IP地址,设备总是先被动的通过ARP先让PC机知道其MAC地址,这样当PC机发送UDP或者TCP报文时,在报文中已经包含了PC机的IP地址,设备仅需从rxtx_buffer中取出PC机IP地址。ARP协议是一个找邻居的过程,是一个广播找MAC的过程。发出者通过广播报文确认某个IP的MAC地址。ARP首部包括,2字节硬件类型,2字节协议类型,1字节硬件长度,1字节协议长度,2字节操作码,6字节发送者硬件地址,4字节发送者IP地址,6字节目标硬件地址和4字节目标IP地址。
在使用ARP协议时需要注意三点
第一,操作码分为两种——ARP请求和ARP响应,ARP请求的编码为1,ARP响应的编码为2,先有请求后有响应。第二,发送ARP协议请求时请求方明确对方IP地址,但是不明确对方MAC地址,所以在请求报文中MAC地址全部以0替代。第三,由于不知道对方的MAC地址,所以只能通过广播帧发送以太网数据,所以以太网首部的前6个字节被FF填充。
为了便于ARP功能的实现,在arp.h文件中定义了以下宏定义
[cpp] view plaincopy

  • #define ARP_PACKET_LEN 28
  • // ARP请求
  • #define ARP_OPCODE_REQUEST_V 0x0001
  • #define ARP_OPCODE_REQUEST_H_V 0x00
  • #define ARP_OPCODE_REQUEST_L_V 0x01
  • // ARP响应
  • #define ARP_OPCODE_REPLY_V 0x0002
  • #define ARP_OPCODE_REPLY_H_V 0x00
  • #define ARP_OPCODE_REPLY_L_V 0x02
  • // 硬件类型 10M以太网
  • #define ARP_HARDWARE_TYPE_H_V 0x00
  • #define ARP_HARDWARE_TYPE_L_V 0x01
  • // 协议类型 IPV4
  • #define ARP_PROTOCOL_H_V 0x08
  • #define ARP_PROTOCOL_L_V 0x00
  • // 硬件地址长度
  • #define ARP_HARDWARE_SIZE_V 0x06
  • // 协议地址长度
  • #define ARP_PROTOCOL_SIZE_V 0x04
  • // 硬件类型 2字节
  • #define ARP_HARDWARE_TYPE_H_P 0x0E
  • #define ARP_HARDWARE_TYPE_L_P 0x0F
  • // 协议类型 2字节
  • #define ARP_PROTOCOL_H_P 0x10
  • #define ARP_PROTOCOL_L_P 0x11
  • // 硬件地址 1字节
  • #define ARP_HARDWARE_SIZE_P 0x12
  • // 协议地址长度 1字节
  • #define ARP_PROTOCOL_SIZE_P 0x13
  • // 操作码 2字节
  • #define ARP_OPCODE_H_P 0x14
  • #define ARP_OPCODE_L_P 0x15
  • // 发送者硬件地址 6字节
  • #define ARP_SRC_MAC_P 0x16
  • // 发送者IP地址 4字节
  • #define ARP_SRC_IP_P 0x1C
  • // 目标硬件地址 6字节
  • #define ARP_DST_MAC_P 0x20
  • // 目标IP地址 6字节
  • #define ARP_DST_IP_P 0x26

    在没有操作系统的支持下,一般通过一个无限循环实现子功能的实现。项目中通过某个process不断查询是否存在网卡数据,如果有网卡数据则立刻保存源MAC地址。因为项目中没有维护ARP表,所以必须及时记录发送方的MAC地址,以便向它返回数据。紧着便是查询该报文是否为ARP请求,如果是ARP请求则返回ARP响应。具体代码如下 :
[cpp] view plaincopy

  • void server_process ( void )  
  • {  
  •     MAC_ADDR client_mac;  
  •     IP_ADDR client_ip;  

  •     WORD plen;  

  •     // 获得新的IP报文
  •     plen = enc28j60_packet_receive( (BYTE*)&rxtx_buffer, MAX_RXTX_BUFFER );  
  •     if(plen==0) return;  

  •     // 保存客服端的MAC地址
  •     memcpy ( (BYTE*)&client_mac, &rxtx_buffer[ ETH_SRC_MAC_P ], sizeof( MAC_ADDR) );  
  •     // 检查该报文是不是ARP报文
  •     if ( arp_packet_is_arp( rxtx_buffer, (WORD_BYTES){ARP_OPCODE_REQUEST_V} ) )  
  •     {  
  •         // 向客户端返回ARP报文
  •         arp_send_reply ( (BYTE*)&rxtx_buffer, (BYTE*)&client_mac );  
  •         return;  
  •     }   
  • }  


4.1 查询ARP报文    查询该报文是否是针对设备的ARP报文需要确认三点,第一:确认以太网首部中的协议类型是否为ARP协议类型,ARP协议类型的值为0806H。第二,查询该ARP报文是否为ARP请求,该步骤需要到ARP首部中查询ARP操作码,ARP请求的操作码为1。第三,查询该ARP请求中的MAC地址是否和本机MAC匹配。
最后通过宏定义ARP_DEBUD决定是否通过串口输出发起者IP地址和MAC地址。通过串口打印可以确认该ARP报文的发起者。
[cpp] view plaincopy

  • BYTE arp_packet_is_arp ( BYTE *rxtx_buffer, WORD_BYTES opcode )  
  • {  
  •     BYTE i;  

  •     // 该报文为ARP报文
  •     if( rxtx_buffer[ ETH_TYPE_H_P ] != ETH_TYPE_ARP_H_V || rxtx_buffer[ ETH_TYPE_L_P ] != ETH_TYPE_ARP_L_V)  
  •         return 0;  
  •     // 确认ARP操作码 ARP请求 1 ARP应答2
  •     if ( rxtx_buffer[ ARP_OPCODE_H_P ] != opcode.byte.high || rxtx_buffer[ ARP_OPCODE_L_P ] != opcode.byte.low )  
  •         return 0;  
  •     // 匹配IP地址
  •     for ( i=0; i<sizeof(IP_ADDR); i++ )  
  •     {  
  •         if ( rxtx_buffer[ ARP_DST_IP_P + i] != stm32_ip.byte )  
  •             return 0;  
  •     }  

  •     // 通过串口输出
  • #if ARP_DEBUG
  •     printf("ARP Message!\r\n");  
  •     printf("Source IP:%d.%d.%d.%d\r\n",\  
  •             rxtx_buffer[ARP_SRC_IP_P+0],rxtx_buffer[ARP_SRC_IP_P+1],\  
  •             rxtx_buffer[ARP_SRC_IP_P+2],rxtx_buffer[ARP_SRC_IP_P+3]);  
  •     printf("Source MAC:%02X-%02X-%02X-%02X-%02X-%02X\r\n",\  
  •         rxtx_buffer[ARP_SRC_MAC_P+0],rxtx_buffer[ARP_SRC_MAC_P+1],\  
  •             rxtx_buffer[ARP_SRC_MAC_P+2],rxtx_buffer[ARP_SRC_MAC_P+3],\  
  •             rxtx_buffer[ARP_SRC_MAC_P+4],rxtx_buffer[ARP_SRC_MAC_P+5]);  
  • #endif
  •     return 1;  
  • }  

继承事业,薪火相传
返回列表