一、phy回环设计框图:
二、实现原理
1、模组的MAC通过RGMII/MII/RMII接口与PHY连接
2、MAC层数据经过RGMII到达PHY的PCS层
3、设置PHY的PCS层回环,使PCS层数据回到MAC层
4、判断MAC层TX与RX接收的数据。如果MAC能接收到数据,测试PASS,否则失败
三、功能实现流程说明
四、代码实现
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>// close()
#include <string.h>// strcpy, memset(), and memcpy()
#include <netdb.h> // struct addrinfo
#include <sys/types.h> // needed for socket(), uint8_t, uint16_t, uint32_t
#include <sys/socket.h> // needed for socket()
#include <netinet/in.h> // IPPROTO_ICMP, INET_ADDRSTRLEN
#include <netinet/ip.h>// struct ip and IP_MAXPACKET (which is 65535)
#include <netinet/ip_icmp.h> // struct icmp, ICMP_ECHO
#include <arpa/inet.h> // inet_pton() and inet_ntop()
#include <sys/ioctl.h> // macro ioctl is defined
#include <bits/ioctls.h> // defines values for argument "request" of ioctl.
#include <net/if.h> // struct ifreq
#include <linux/if_ether.h> // ETH_P_IP = 0x0800, ETH_P_IPV6 = 0x86DD
#include <linux/if_packet.h> // struct sockaddr_ll (see man 7 packet)
#include <net/ethernet.h>
#include <errno.h> // errno, perror()
#define ETH_P_DEAN 0x8874 //自定义的以太网协议type
int main(int argc, char **argv)
{
int i, datalen, frame_length, sd, bytes;
char *interface = "eth0";
uint8_t data[IP_MAXPACKET];
uint8_t src_mac[6];
uint8_t dst_mac[6];
uint8_t ether_frame[IP_MAXPACKET] = {0};
struct sockaddr_ll device;
struct ifreq ifr;
int recvlen=0;
uint8_t buffer[IP_MAXPACKET] = {0};
int loopback_state=1;
// Submit request for a socket descriptor to look up interface.
if ((sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) {
perror("socket() failed to get socket descriptor for using ioctl()");
exit(EXIT_FAILURE);
}
// Use ioctl() to look up interface name and get its MAC address.
memset(&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", interface);
if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
{
perror("ioctl() failed to get source MAC address ");
return (EXIT_FAILURE);
}
close(sd);
// Copy source MAC address.
memcpy(src_mac, ifr.ifr_hwaddr.sa_data, 6);
// Report source MAC address to stdout.
printf("MAC address for interface %s is ", interface);
for (i = 0; i < 5; i++)
{
printf("%02x:", src_mac[i]);
}
printf("%02x\n", src_mac[5]);
// Find interface index from interface name and store index in
// struct sockaddr_ll device, which will be used as an argument of sendto().
memset(&device, 0, sizeof(device));
if ((device.sll_ifindex = if_nametoindex(interface)) == 0)
{
perror("if_nametoindex() failed to obtain interface index ");
exit(EXIT_FAILURE);
}
printf("Index for interface %s is %i\n", interface, device.sll_ifindex);
// Set destination MAC address: you need to fill these out
dst_mac[0] = 0x10; //设置目的网卡地址
dst_mac[1] = 0x78;
dst_mac[2] = 0xd2;
dst_mac[3] = 0xc6;
dst_mac[4] = 0x2f;
dst_mac[5] = 0x89;
// Fill out sockaddr_ll.
device.sll_family = AF_PACKET;
memcpy(device.sll_addr, src_mac, 6);
device.sll_halen = htons(6);
// 发送的data,长度可以任意,但是抓包时看到最小数据长度为46,这是以太网协议规定以太网帧数
//据域部分最小为46字节,不足的自动补零处理
datalen = 12;
data[0] = 'h';
data[1] = 'e';
data[2] = 'l';
data[3] = 'l';
data[4] = 'o';
data[5] = ' ';
data[6] = 'w';
data[7] = 'o';
data[8] = 'r';
data[9] = 'l';
data[10] = 'd';
data[11] = '!';
// Fill out ethernet frame header.
frame_length = 6 + 6 + 2 + datalen;
// Destination and Source MAC addresses
memcpy(ether_frame, dst_mac, 6);
memcpy(ether_frame + 6, src_mac, 6);
ether_frame[12] = ETH_P_DEAN / 256;
ether_frame[13] = ETH_P_DEAN % 256;
// data
memcpy(ether_frame + 14, data, datalen);
// Submit request for a raw socket descriptor.
if ((sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0)
{ //创建正真发送的socket
perror("socket() failed ");
exit(EXIT_FAILURE);
}
// Send ethernet frame to socket.
if ((bytes = sendto(sd, ether_frame, frame_length, 0, (struct sockaddr *)&device,
sizeof(device))) <= 0)
{
perror("sendto() failed");
exit(EXIT_FAILURE);
}
printf("IP_MAXPACKET = %d\nbytes = %d sendto data:\n", IP_MAXPACKET, bytes);
for(i=0;i<bytes;i++){
printf(" %02x",ether_frame[i]);
if((i+1)%16==0){
printf("\n");
}
}
printf("\n");
recvlen = recvfrom(sd,buffer,sizeof(buffer),0,NULL,NULL);
printf("recvlen = %d recvfrom data:\n", recvlen);
for (i=0;i<recvlen;i++) {
printf(" %02x",buffer[i]);
if((i+1)%16==0){
printf("\n");
}
}
printf("\n");
for(i=0; i<recvlen; i++) {
if(bytes>recvlen)
{
loopback_state=0;
break;
}
else if(ether_frame[i]!=buffer[i])
{
loopback_state=0;
printf("ether_frame[%d]:%02x buffer[%d]:%02x\n", i, ether_frame[i], i, buffer[i]);
break;
}
}
if (loopback_state == 1)
{
printf("phy loopback OK\n");
}
else
{
printf("phy loopback error\n");
}
// Close socket descriptor.
close(sd);
return (EXIT_SUCCESS);
}