// SPDX-License-Identifier: Apache-2.0 /* * Copyright (C) 2023 Artinchip Technology Co., Ltd. * Authors: wulv */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define UDP_BUF_SIZE 256 #define DEFAULT_SLEEP_TIME 1000000 #define DEFAULT_TEST_COUNT 500 #define FRAME_TYPE 0xFFFF #define CMD_SIZE IFNAMSIZ + 15 /* eth max name + strlen("ifconfig %s down") */ #define USAGE \ "Usage: test_eth [-n count] [-d delay] [-i eth0]\n" \ "example: test_eth -n 100 -d 0 -i eth0\n" \ "Options:\n" \ " -n count Number of echo frame to test, default 500.\n" \ " -d delay Delay time(S) between two loopback test,default 0.\n" \ " -i eth_name Select the name of the network card, such as eth0 or eth1 ..., default eth0.\n" static int phy_link_poll(int socket_fd, struct ifreq *ethreq, int timeout_s) { do { if (ioctl(socket_fd, SIOCGIFFLAGS, ethreq) < 0) { printf("Failed to get %s flags\n", ethreq->ifr_name); return -1; } if ((ethreq->ifr_flags & IFF_RUNNING) != 0) break; sleep(1); printf("Wait for phy connected...\n"); }while(timeout_s-- > 0); if (timeout_s <= 0) return -1; return 0; } static int sock_timeout_set_1s(int socket_fd) { struct timeval timeout; int ret_val; timeout.tv_sec = 1; timeout.tv_usec = 0; ret_val = setsockopt(socket_fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); if (ret_val != 0) { printf("SO_SNDTIMEO set error!\n"); return -1; } ret_val = setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); if (ret_val != 0) { printf("SO_RCVTIMEO set error!\n"); return -1; } return 0; } int main(int argc, char **argv) { int ret_val; int socket_fd; unsigned int count = 0; unsigned int max_count = DEFAULT_TEST_COUNT; unsigned int delay_s = 0; char ethx[IFNAMSIZ + 4] = {"eth0"}; char cmd[CMD_SIZE] = {0}; struct ifreq ethreq = {0}; int c; char *end; char ethernet_recv_buf[UDP_BUF_SIZE]; const char ethernet_send_msg[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 'A','r','t','I','n','C','h','i','p', 0xA5,0x5A,0xA5,0x5A,0xA5,0x5A, 0xA5,0x5A,0xA5,0x5A,0xA5,0x5A, 0xA5,0x5A,0xA5,0x5A,0xA5,0x5A, 0xA5,0x5A,0xA5,0x5A,0xA5,0x5A, 0xA5,0x5A,0xA5,0x5A,0xA5,0x5A, 0xA5,0x5A,0xA5,0x5A,0xA5,0x5A, 0xA5,0x5A,0xA5,0x5A,0xA5,0x5A, 0xA5,0x5A,0xA5,0x5A,0xA5,0x5A, 0xA5,0x5A,0xA5,0x5A,0xA5,0x5A, }; struct sockaddr_ll *sll; int poll_times_s = 5; size_t leng; if (argc > 7) { printf("Argument error\n"); exit(-1); } while ((c = getopt(argc, argv, "n:d:i:h")) != -1) { switch (c) { case 'd': if (optarg) delay_s = strtoul(optarg, &end, 10); if (end == NULL) { printf("%s", USAGE); exit(-1); } break; case 'n': max_count = strtoul(optarg, &end, 10); if (end == NULL) { printf("%s", USAGE); exit(-1); } break; case 'i': if (strncpy(ethx, optarg, IFNAMSIZ) == NULL) { printf("%s", USAGE); exit(-1); } break; case 'h': default: printf("%s", USAGE); exit(-1); } } /* start up net interface */ leng = strlen(ethx); snprintf(cmd, CMD_SIZE, "ifconfig %.*s up", (int)leng, ethx); system(cmd); socket_fd = socket(AF_PACKET, SOCK_RAW, htons(FRAME_TYPE)); if (socket_fd < 0) { printf("socket alloc error!\n"); exit(-1); } sll = (struct sockaddr_ll *)malloc(sizeof(struct sockaddr_ll)); if (sll == NULL) { printf("sockaddr_ll malloc error\n"); close(socket_fd); exit(-1); } strncpy(ethreq.ifr_name, ethx, IFNAMSIZ); /* check phy connected */ if (phy_link_poll(socket_fd, ðreq, poll_times_s) < 0) { printf("Phy connect timeout...\n"); goto out; } /* bind net interface */ if (ioctl(socket_fd, SIOCGIFINDEX, ðreq) < 0) { printf("Failed to bind interface: %s\n", ethreq.ifr_name); goto out; } sll->sll_ifindex = ethreq.ifr_ifindex; /* set socket send/recv timeout 1S */ if (sock_timeout_set_1s(socket_fd) < 0) { goto out; } while (1) { ret_val = sendto(socket_fd, ethernet_send_msg, sizeof(ethernet_send_msg), 0, (void *)sll, sizeof(*sll)); if (ret_val <= 0) { printf("send error! errno is: %d\n", errno); goto err_out; } ret_val = recvfrom(socket_fd, ethernet_recv_buf, UDP_BUF_SIZE, 0, NULL, NULL); if (ret_val <= 0) { printf("recv error! errno is:%d\n", errno); goto err_out; } if (memcmp(ethernet_send_msg, ethernet_recv_buf, sizeof(ethernet_send_msg)) != 0) { printf("Test frame mismatch error\n"); goto err_out; } printf("Ethernet circle test round :%d OK\n", count + 1); if (++count >= max_count) { printf("Ethernet circle test OK. totle: %d\n", count); goto out; } if (delay_s != 0) { sleep(delay_s); } } err_out: printf("Ethernet circle test error, success count %d\n", count); out: free(sll); close(socket_fd); snprintf(cmd, CMD_SIZE, "ifconfig %.*s down", (int)leng, ethx); system(cmd); exit(0); }