mirror of
https://github.com/apache/nuttx-apps.git
synced 2026-08-09 06:25:16 +00:00
add cmock_test for enet in order to test send and receive pkt Signed-off-by: zhangkai25 <zhangkai25@xiaomi.com>
284 lines
7.5 KiB
C
284 lines
7.5 KiB
C
/****************************************************************************
|
|
* apps/testing/enet/util/enet_util.c
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership. The
|
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance with the
|
|
* License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations
|
|
* under the License.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include "enet_util.h"
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/socket.h>
|
|
#include <net/if.h>
|
|
#include <netinet/in.h>
|
|
#include <netpacket/packet.h>
|
|
|
|
/****************************************************************************
|
|
* Pre-processor Definitions
|
|
****************************************************************************/
|
|
|
|
#define DATA_SIZE 200
|
|
|
|
#define ETH_PTP_TYPE 0x88f7
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: enet_test_setup
|
|
****************************************************************************/
|
|
|
|
int enet_test_setup(void **state)
|
|
{
|
|
struct senet_testsuites_params *enet_p;
|
|
int ret;
|
|
|
|
enet_p = zalloc(sizeof(struct senet_testsuites_params));
|
|
assert_true(enet_p != NULL);
|
|
enet_p->enet_dev.if_name = strdup(CONFIG_ENET_TEST_DEV);
|
|
*state = enet_p;
|
|
|
|
/* ifup enet interface */
|
|
|
|
ret = netlib_ifup(enet_p->enet_dev.if_name);
|
|
assert_true(ret == 0);
|
|
enet_p->enet_dev.fd = enet_test_init(enet_p->enet_dev.if_name);
|
|
assert_true(enet_p->enet_dev.fd > 0);
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: enet_test_init
|
|
****************************************************************************/
|
|
|
|
int enet_test_init(const char *enetif)
|
|
{
|
|
int ret;
|
|
int pkt_fd;
|
|
struct sockaddr_ll sll;
|
|
struct timeval timeout;
|
|
struct ifreq ifr;
|
|
int ifindex;
|
|
int optval;
|
|
|
|
/* Create raw socket */
|
|
|
|
pkt_fd = socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, HTONS(ETH_PTP_TYPE));
|
|
assert_true(pkt_fd > 0);
|
|
|
|
/* Initialize socket address structure */
|
|
|
|
memset(&sll, 0, sizeof(struct sockaddr_ll));
|
|
|
|
/* Set socket timeout options */
|
|
|
|
timeout.tv_sec = 0;
|
|
timeout.tv_usec = 1;
|
|
|
|
ret = setsockopt(pkt_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout,
|
|
sizeof(timeout));
|
|
assert_true(ret == 0);
|
|
|
|
ret = setsockopt(pkt_fd, SOL_SOCKET, SO_SNDTIMEO, &timeout,
|
|
sizeof(timeout));
|
|
assert_true(ret == 0);
|
|
|
|
/* Set don't route option */
|
|
|
|
optval = 1;
|
|
ret = setsockopt(pkt_fd, SOL_SOCKET, SO_DONTROUTE, &optval,
|
|
sizeof(optval));
|
|
assert_true(ret == 0);
|
|
|
|
/* Get interface index */
|
|
|
|
strlcpy(ifr.ifr_name, enetif, IFNAMSIZ);
|
|
ret = ioctl(pkt_fd, SIOCGIFINDEX, &ifr);
|
|
assert_true(ret == 0);
|
|
|
|
ifindex = ifr.ifr_ifindex;
|
|
|
|
/* Get interface flags */
|
|
|
|
ret = ioctl(pkt_fd, SIOCGIFFLAGS, &ifr);
|
|
assert_true(ret == 0);
|
|
|
|
/* Set interface broadcast flag */
|
|
|
|
ifr.ifr_flags |= IFF_BROADCAST;
|
|
ret = ioctl(pkt_fd, SIOCSIFFLAGS, &ifr);
|
|
assert_true(ret == 0);
|
|
|
|
/* Prepare and bind socket */
|
|
|
|
sll.sll_family = AF_PACKET;
|
|
sll.sll_protocol = HTONS(ETH_PTP_TYPE);
|
|
sll.sll_ifindex = ifindex;
|
|
|
|
ret = bind(pkt_fd, (struct sockaddr *)&sll,
|
|
sizeof(struct sockaddr_ll));
|
|
assert_true(ret == 0);
|
|
|
|
return pkt_fd;
|
|
|
|
errout_with_socket:
|
|
close(pkt_fd);
|
|
return -1;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: enet_loop_send_frame
|
|
* Description:
|
|
* Test sending ethernet frames in a loop (20 times)
|
|
****************************************************************************/
|
|
|
|
void enet_loop_send_frame(void **state)
|
|
{
|
|
struct senet_testsuites_params *enet_if = *state;
|
|
uint8_t data[DATA_SIZE];
|
|
const char *message = "Hello, World!";
|
|
uint16_t ip_checksum;
|
|
int ret;
|
|
size_t message_len;
|
|
int i;
|
|
const int LOOP_COUNT = 20; /* Number of frames to send */
|
|
|
|
/* Initialize test data */
|
|
|
|
memset(data, 0, DATA_SIZE);
|
|
|
|
/* Setup ethernet header */
|
|
|
|
/* Destination MAC address (broadcast) */
|
|
|
|
data[0] = 0x01; data[1] = 0x00; data[2] = 0x5e;
|
|
data[3] = 0x00; data[4] = 0x00; data[5] = 0x00;
|
|
|
|
/* Source MAC address: 58:32:31:32:39:37 */
|
|
|
|
data[6] = 0x58; data[7] = 0x32; data[8] = 0x31;
|
|
data[9] = 0x32; data[10] = 0x39; data[11] = 0x37;
|
|
|
|
/* Ethernet type (IPv4) */
|
|
|
|
data[12] = 0x88; data[13] = 0xf7;
|
|
|
|
/* Setup IP header */
|
|
|
|
data[14] = 0x45; /* Version 4, IHL 5 (20 bytes) */
|
|
data[15] = 0x00; /* DSCP/ECN */
|
|
data[16] = 0x00; data[17] = 0x4e; /* Total Length: 78 bytes */
|
|
data[18] = 0x00; data[19] = 0x00; /* Identification */
|
|
data[20] = 0x00; data[21] = 0x00; /* Flags and Fragment Offset */
|
|
data[22] = 0x40; /* TTL: 64 */
|
|
data[23] = 0x11; /* Protocol: UDP */
|
|
data[24] = 0x00; data[25] = 0x00; /* Header Checksum (initial 0) */
|
|
|
|
/* Source IP: 10.0.0.2 */
|
|
|
|
data[26] = 0x0a; data[27] = 0x00;
|
|
data[28] = 0x00; data[29] = 0x02;
|
|
|
|
/* Destination IP: 255.255.255.255 (broadcast) */
|
|
|
|
data[30] = 0xff; data[31] = 0xff;
|
|
data[32] = 0xff; data[33] = 0xff;
|
|
|
|
/* Copy payload message */
|
|
|
|
message_len = strlen(message);
|
|
memcpy(data + 42, message, message_len);
|
|
|
|
/* Calculate IP header checksum */
|
|
|
|
ip_checksum = 0;
|
|
for (int i = 14; i < 34; i += 2)
|
|
{
|
|
ip_checksum += (data[i] << 8) | data[i + 1];
|
|
}
|
|
|
|
if (ip_checksum >> 16)
|
|
{
|
|
ip_checksum = (ip_checksum & 0xffff) + (ip_checksum >> 16);
|
|
}
|
|
|
|
ip_checksum = ~ip_checksum;
|
|
data[24] = (ip_checksum >> 8) & 0xff;
|
|
data[25] = ip_checksum & 0xff;
|
|
|
|
/* Send frames in a loop */
|
|
|
|
for (i = 0; i < LOOP_COUNT; i++)
|
|
{
|
|
ret = send(enet_if->enet_dev.fd, data, DATA_SIZE, 0);
|
|
assert_true(ret > 0);
|
|
|
|
/* Add a small delay between sends */
|
|
|
|
usleep(100000); /* 100ms delay */
|
|
}
|
|
|
|
/* Verify we completed all sends */
|
|
|
|
assert_true(i == LOOP_COUNT);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: enet_test_teardown
|
|
****************************************************************************/
|
|
|
|
int enet_test_teardown(void **state)
|
|
{
|
|
int ret;
|
|
struct senet_testsuites_params *enet_p;
|
|
|
|
if (state == NULL || *state == NULL)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
enet_p = *state;
|
|
|
|
/* close enet interface */
|
|
|
|
ret = close(enet_p->enet_dev.fd);
|
|
assert_true(ret == 0);
|
|
ret = netlib_ifdown(enet_p->enet_dev.if_name);
|
|
assert_true(ret >= 0);
|
|
|
|
/* free memory */
|
|
|
|
free(enet_p->enet_dev.if_name);
|
|
|
|
/* free structure */
|
|
|
|
free(enet_p);
|
|
*state = NULL;
|
|
return 0;
|
|
}
|