fixed i forgot about but seem to work

This commit is contained in:
cozis
2023-08-29 01:10:02 +02:00
parent 59e6238348
commit 6bfb514df7
9 changed files with 666 additions and 147 deletions
+7
View File
@@ -109,6 +109,8 @@ build/microtcp.c: 3p/include/tinycthread.h 3p/src/tinycthread.c $(wildcard src/*
printf "\n#endif /* MICROTCP_BACKGROUND_THREAD */" >> $@
printf "\n#line 1 \"src/defs.h\"\n" >> $@
cat src/defs.h >> $@
printf "\n#line 1 \"src/utils.h\"\n" >> $@
cat src/utils.h >> $@
printf "\n#line 1 \"src/endian.h\"\n" >> $@
cat src/endian.h >> $@
printf "\n#line 1 \"src/arp.h\"\n" >> $@
@@ -121,6 +123,8 @@ build/microtcp.c: 3p/include/tinycthread.h 3p/src/tinycthread.c $(wildcard src/*
cat src/tcp_timer.h >> $@
printf "\n#line 1 \"src/tcp.h\"\n" >> $@
cat src/tcp.h >> $@
printf "\n#line 1 \"src/utils.c\"\n" >> $@
cat src/utils.c >> $@
printf "\n#line 1 \"src/endian.c\"\n" >> $@
cat src/endian.c >> $@
printf "\n#line 1 \"src/arp.c\"\n" >> $@
@@ -142,6 +146,9 @@ build/echo_http: examples/microhttp/main.c $(LIBDIR)/libtuntap.a 3p/include/tunt
build/test: tests/test.c tests/test_tcp_timer.c src/tcp_timer.c src/tcp_timer.h
gcc -fprofile-arcs -ftest-coverage tests/test.c tests/test_tcp_timer.c src/tcp_timer.c -o $@ -Wall -Wextra -DTCP_MAX_TIMERS=4
build/test_arp: tests/test_arp.c
gcc tests/test_arp.c -o build/test_arp -Wall -Wextra
report: build/test
./build/test
gcov -b build/test-tcp_timer.c
+4 -13
View File
@@ -128,19 +128,6 @@ struct ethhdr {
#define ARP_DEBUG_LOG(...)
#endif
typedef enum {
ARP_HARDWARE_ETHERNET = 1,
} arp_hardware_type;
typedef enum {
ARP_PROTOCOL_IP = 0x800,
} arp_protocol_type;
typedef enum {
ARP_OPERATION_REQUEST = 1,
ARP_OPERATION_REPLY = 2,
} arp_operation_t;
void arp_change_output_buffer(arp_state_t *state, void *ptr, size_t max)
{
if (max < sizeof(arp_packet_t))
@@ -619,6 +606,7 @@ void arp_resolve_mac(arp_state_t *state, ip_address_t ip, void *userp, void (*ca
append_pending_request_to_used_list(state, pending_request);
arp_packet_t *packet = state->output;
if (packet != NULL) {
packet->hardware_type = cpu_to_net_u16(ARP_HARDWARE_ETHERNET);
packet->protocol_type = cpu_to_net_u16(ARP_PROTOCOL_IP);
packet->hardware_len = 6;
@@ -632,6 +620,9 @@ void arp_resolve_mac(arp_state_t *state, ip_address_t ip, void *userp, void (*ca
ARP_DEBUG_LOG("Sending out ARP request to resolve MAC");
state->send(state->send_data, MAC_BROADCAST);
} else {
ARP_DEBUG_LOG("Couldn't send ARP request because no output buffer was provided");
}
}
}
+30 -3
View File
@@ -42,6 +42,19 @@ struct arp_pending_request_t {
void (*callback)(void*, arp_resolution_status_t status, mac_address_t);
};
typedef enum {
ARP_HARDWARE_ETHERNET = 1,
} arp_hardware_type;
typedef enum {
ARP_PROTOCOL_IP = 0x800,
} arp_protocol_type;
typedef enum {
ARP_OPERATION_REQUEST = 1,
ARP_OPERATION_REPLY = 2,
} arp_operation_t;
typedef struct __attribute__((__packed__)) {
uint16_t hardware_type;
uint16_t protocol_type;
@@ -93,9 +106,23 @@ typedef enum {
ARP_PROCESS_RESULT_OK,
} arp_process_result_t;
void arp_init(arp_state_t *state, ip_address_t ip, mac_address_t mac, void *send_data, void (*send)(void*, mac_address_t));
void arp_init(arp_state_t *state,
ip_address_t ip,
mac_address_t mac,
void *send_data,
void (*send)(void*, mac_address_t));
void arp_free(arp_state_t *state);
arp_process_result_t arp_process_packet(arp_state_t *state, const void *packet, size_t len);
void arp_resolve_mac(arp_state_t *state, ip_address_t ip, void *userp, void (*callback)(void*, arp_resolution_status_t, mac_address_t));
arp_process_result_t
arp_process_packet(arp_state_t *state,
const void *packet,
size_t len);
void arp_resolve_mac(arp_state_t *state,
ip_address_t ip,
void *userp,
void (*callback)(void*, arp_resolution_status_t, mac_address_t));
void arp_seconds_passed(arp_state_t *state, size_t seconds);
void arp_change_output_buffer(arp_state_t *state, void *ptr, size_t max);
+1 -119
View File
@@ -1,5 +1,4 @@
#include <time.h> // time()
#include <ctype.h>
#include <errno.h>
#include <string.h> // strerror()
#include <stdint.h>
@@ -9,6 +8,7 @@
# include "ip.h"
# include "arp.h"
# include "tcp.h"
# include "utils.h"
# include "endian.h"
# include "microtcp.h"
# ifdef MICROTCP_BACKGROUND_THREAD
@@ -435,124 +435,6 @@ static int loop(void *data)
}
#endif
static bool is_hex_digit(char c)
{
return (c >= '0' && c <= '9')
|| (c >= 'a' && c <= 'f')
|| (c >= 'A' && c <= 'F');
}
static int int_from_hex_digit(char c)
{
assert(is_hex_digit(c));
if (c >= 'A' || c <= 'F')
return c - 'A' + 10;
if (c >= 'a' || c <= 'f')
return c - 'a' + 10;
return c - '0';
}
static bool parse_mac(const char *src, size_t len,
mac_address_t *mac)
{
if (src == NULL || len != 17
|| !is_hex_digit(src[0])
|| !is_hex_digit(src[1])
|| src[2] != ':'
|| !is_hex_digit(src[3])
|| !is_hex_digit(src[4])
|| src[5] != ':'
|| !is_hex_digit(src[6])
|| !is_hex_digit(src[7])
|| src[8] != ':'
|| !is_hex_digit(src[9])
|| !is_hex_digit(src[10])
|| src[11] != ':'
|| !is_hex_digit(src[12])
|| !is_hex_digit(src[13])
|| src[14] != ':'
|| !is_hex_digit(src[15])
|| !is_hex_digit(src[16]))
return false;
static const char max_char_map[] = "0123456789ABCDEF";
if (mac) {
mac->data[0] = max_char_map[int_from_hex_digit(src[ 0])] << 4
| max_char_map[int_from_hex_digit(src[ 1])];
mac->data[1] = max_char_map[int_from_hex_digit(src[ 3])] << 4
| max_char_map[int_from_hex_digit(src[ 4])];
mac->data[2] = max_char_map[int_from_hex_digit(src[ 6])] << 4
| max_char_map[int_from_hex_digit(src[ 7])];
mac->data[3] = max_char_map[int_from_hex_digit(src[ 9])] << 4
| max_char_map[int_from_hex_digit(src[10])];
mac->data[4] = max_char_map[int_from_hex_digit(src[12])] << 4
| max_char_map[int_from_hex_digit(src[13])];
mac->data[5] = max_char_map[int_from_hex_digit(src[15])] << 4
| max_char_map[int_from_hex_digit(src[16])];
}
return true;
}
static mac_address_t generate_random_mac()
{
mac_address_t mac = {
.data = {
rand() & 0xff,
rand() & 0xff,
rand() & 0xff,
rand() & 0xff,
rand() & 0xff,
rand() & 0xff,
},
};
return mac;
}
static bool parse_ip(const char *ip, ip_address_t *parsed_ip)
{
size_t len = strlen(ip);
size_t i = 0;
uint32_t value = 0;
for (size_t k = 0; k < 4; k++) {
if (i == len || !isdigit(ip[i]))
return false;
int n = 0; // Used to represent a byte, but it's larger
// to detect overflows.
do {
// Convert character to number
int digit = ip[i] - '0';
if (n > (UINT8_MAX - digit)/10)
// Adding this digit would make the
// byte overflow, so it can't be part
// of the octet.
break;
n = n * 10 + digit;
i++;
} while (i < len && isdigit(ip[i]));
assert(n >= 0 && n <= UINT8_MAX);
value = (value << 8) | (uint8_t) n;
// If this isn't the last octet and there is no
// dot following it, the address is invalid.
if (k < 3) {
if (i == len || ip[i] != '.')
return false;
i++; // Consume the dot.
}
}
if (i < len)
// source string contains something
// other than the address in it.
return false;
*parsed_ip = cpu_to_net_u32(value);
return true;
}
microtcp_t *microtcp_create_using_callbacks(const char *ip, const char *mac,
microtcp_callbacks_t callbacks)
{
+2
View File
@@ -409,6 +409,8 @@ static void timeout_callback_time_wait(void *data)
tcp_connection_t *connection = data;
assert(connection->state == TCP_STATE_TIME_WAIT);
TCP_DEBUG_LOG("TIME-WAIT -> CLOSED");
// We can finally free up this connection structure!
really_close_connection(connection);
}
+127
View File
@@ -0,0 +1,127 @@
#include <ctype.h>
#include <stdlib.h> // rand
#include <string.h>
#ifndef MICROTCP_AMALGAMATION
#include "utils.h"
#include "endian.h"
#endif
static bool is_hex_digit(char c)
{
return (c >= '0' && c <= '9')
|| (c >= 'a' && c <= 'f')
|| (c >= 'A' && c <= 'F');
}
static int int_from_hex_digit(char c)
{
assert(is_hex_digit(c));
if (c >= 'A' || c <= 'F')
return c - 'A' + 10;
if (c >= 'a' || c <= 'f')
return c - 'a' + 10;
return c - '0';
}
bool parse_mac(const char *src, size_t len,
mac_address_t *mac)
{
if (src == NULL || len != 17
|| !is_hex_digit(src[0])
|| !is_hex_digit(src[1])
|| src[2] != ':'
|| !is_hex_digit(src[3])
|| !is_hex_digit(src[4])
|| src[5] != ':'
|| !is_hex_digit(src[6])
|| !is_hex_digit(src[7])
|| src[8] != ':'
|| !is_hex_digit(src[9])
|| !is_hex_digit(src[10])
|| src[11] != ':'
|| !is_hex_digit(src[12])
|| !is_hex_digit(src[13])
|| src[14] != ':'
|| !is_hex_digit(src[15])
|| !is_hex_digit(src[16]))
return false;
static const char max_char_map[] = "0123456789ABCDEF";
if (mac) {
mac->data[0] = max_char_map[int_from_hex_digit(src[ 0])] << 4
| max_char_map[int_from_hex_digit(src[ 1])];
mac->data[1] = max_char_map[int_from_hex_digit(src[ 3])] << 4
| max_char_map[int_from_hex_digit(src[ 4])];
mac->data[2] = max_char_map[int_from_hex_digit(src[ 6])] << 4
| max_char_map[int_from_hex_digit(src[ 7])];
mac->data[3] = max_char_map[int_from_hex_digit(src[ 9])] << 4
| max_char_map[int_from_hex_digit(src[10])];
mac->data[4] = max_char_map[int_from_hex_digit(src[12])] << 4
| max_char_map[int_from_hex_digit(src[13])];
mac->data[5] = max_char_map[int_from_hex_digit(src[15])] << 4
| max_char_map[int_from_hex_digit(src[16])];
}
return true;
}
mac_address_t generate_random_mac()
{
mac_address_t mac = {
.data = {
rand() & 0xff,
rand() & 0xff,
rand() & 0xff,
rand() & 0xff,
rand() & 0xff,
rand() & 0xff,
},
};
return mac;
}
bool parse_ip(const char *ip, ip_address_t *parsed_ip)
{
size_t len = strlen(ip);
size_t i = 0;
uint32_t value = 0;
for (size_t k = 0; k < 4; k++) {
if (i == len || !isdigit(ip[i]))
return false;
int n = 0; // Used to represent a byte, but it's larger
// to detect overflows.
do {
// Convert character to number
int digit = ip[i] - '0';
if (n > (UINT8_MAX - digit)/10)
// Adding this digit would make the
// byte overflow, so it can't be part
// of the octet.
break;
n = n * 10 + digit;
i++;
} while (i < len && isdigit(ip[i]));
assert(n >= 0 && n <= UINT8_MAX);
value = (value << 8) | (uint8_t) n;
// If this isn't the last octet and there is no
// dot following it, the address is invalid.
if (k < 3) {
if (i == len || ip[i] != '.')
return false;
i++; // Consume the dot.
}
}
if (i < len)
// source string contains something
// other than the address in it.
return false;
*parsed_ip = cpu_to_net_u32(value);
return true;
}
+9
View File
@@ -0,0 +1,9 @@
#include <stdbool.h>
#ifndef MICROTCP_AMALGAMATION
#include "defs.h"
#endif
bool parse_mac(const char *src, size_t len, mac_address_t *mac);
bool parse_ip(const char *ip, ip_address_t *parsed_ip);
mac_address_t generate_random_mac();
+11
View File
@@ -0,0 +1,11 @@
@type [ARP]
@desc
Peer requests host's MAC given its IP and host replies.
@IP [10.0.0.4]
@MAC [56:34:f5:4d:4f:44]
@timeline
<= [ ETHERNET | IP | 6 | 4 | REQUEST | 00:34:56:34:f5:4f | 10.0.0.5 | 00:00:00:00:00:00 | 10.0.0.4 ]
=> [ ETHERNET | IP | 6 | 4 | REPLY | 56:34:f5:4d:4f:44 | 10.0.0.4 | 00:34:56:34:f5:4f | 10.0.0.5 ]
+463
View File
@@ -0,0 +1,463 @@
#include <stdio.h>
#include <string.h>
#include "../src/utils.c"
#include "../src/endian.c"
#include "../src/arp.c"
/*
BLACK BOX TEST CASES
A) Peer requests host's MAC given its IP and host
replies.
B) Peer requests host's non MAC level 2 address
given its IP and host doesn't reply because it
only supports MAC.
C) Peer requests host's MAC address given its non
IP level 3 address and host doesn't reply
because it only supports IP.
D) Peer requests host's MAC given its IP, but the
MAC address length field isn't 6, therefore
host doesn't reply.
E) Peer requests host's MAC given its IP, but the
IP address length field isn't 4, therefore host
doesn't reply.
F) Peer sends a request/reply that doesn't refer
to host and is from a sender with IP never seen
by the host (no entry in the translation table).
It's expected that no entry is added to the
translation table.
G) Peer sends a request/reply that doesn't refer
to host but is from a sender with IP already
in the ARP translation table, therefore is
expected that host updates the entry.
H) Program queries the ARP module for a MAC that
isn't cached, therefore an ARP request is
expected to be generated and, when replied to,
the ARP module is expected to resolve the
program's query.
I) Program queries the ARP module for a MAC that's
cached, therefore the ARP module is expected to
resolve it without sending packets.
*/
typedef enum {
TEST_PASSED,
TEST_FAILED,
TEST_ABORTED,
} test_result_t;
#define OUTPUT_QUEUE_SIZE 8
typedef struct {
arp_state_t *state;
arp_packet_t queue[OUTPUT_QUEUE_SIZE];
int count;
int oflow;
} output_queue_t;
static void send_arp_packet_callback(void *data, mac_address_t mac)
{
output_queue_t *oq = (output_queue_t*) data;
if (oq->count == OUTPUT_QUEUE_SIZE)
oq->oflow++;
else {
oq->count++;
if (oq->count == OUTPUT_QUEUE_SIZE)
arp_change_output_buffer(oq->state, NULL, 0);
else
arp_change_output_buffer(oq->state, oq->queue+oq->count, sizeof(arp_packet_t));
}
}
test_result_t test_arp_bb_A(char *msg, size_t msgmax)
{
// Addresses of the packets that will be sent towards
// the ARP module
const char net_ip_str[] = "10.0.0.5";
const char net_mac_str[] = "00:34:56:34:f5:4f";
// Addresses of the ARP module
const char ip_str[] = "10.0.0.4";
const char mac_str[] = "56:34:f5:4d:4f:44";
// Parse the addresses to binary form
ip_address_t ip, net_ip;
mac_address_t mac, net_mac;
if (!parse_mac(mac_str, sizeof(mac_str)-1, &mac) ||
!parse_ip(ip_str, &ip) ||
!parse_mac(net_mac_str, sizeof(net_mac_str)-1, &net_mac) ||
!parse_ip(net_ip_str, &net_ip)) {
snprintf(msg, msgmax, "Couldn't parse IP and MAC strings");
return TEST_ABORTED;
}
// Set up the module with the output queue
arp_state_t state;
output_queue_t oq = {.state=&state, .count=0, .oflow=0}; // Buffer where replies and requests will be stored
// by the ARP module
arp_init(&state, ip, mac, &oq, send_arp_packet_callback);
arp_change_output_buffer(&state, oq.queue, sizeof(arp_packet_t));
// Build the request
arp_packet_t request = {
.hardware_type = cpu_to_net_u16(ARP_HARDWARE_ETHERNET),
.protocol_type = cpu_to_net_u16(ARP_PROTOCOL_IP),
.hardware_len = 6,
.protocol_len = 4,
.operation_type = cpu_to_net_u16(ARP_OPERATION_REQUEST),
.sender_hardware_address = net_mac,
.sender_protocol_address = net_ip,
.target_hardware_address = MAC_ZERO,
.target_protocol_address = ip,
};
// Send the request
arp_process_result_t res;
res = arp_process_packet(&state, &request, sizeof(arp_packet_t));
switch (res) {
case ARP_PROCESS_RESULT_HWARENOTSUPP:
case ARP_PROCESS_RESULT_PROTONOTSUPP:
case ARP_PROCESS_RESULT_INVALID:
snprintf(msg, msgmax, "ARP module couldn't process request");
return TEST_FAILED;
case ARP_PROCESS_RESULT_OK:
break;
}
// Make sure that the module replies one time and one time only
if (oq.count == 0) {
// The ARP module sent no reply given
// our request.
snprintf(msg, msgmax, "ARP module didn't reply");
return TEST_FAILED;
}
if (oq.count > 1) {
// Sent too many replies
snprintf(msg, msgmax, "ARP module replied too many times");
return TEST_FAILED;
}
// Check that the reply has the right content
arp_packet_t *reply = oq.queue;
if (net_to_cpu_u16(reply->hardware_type) != ARP_HARDWARE_ETHERNET ||
net_to_cpu_u16(reply->protocol_type) != ARP_PROTOCOL_IP ||
net_to_cpu_u16(reply->operation_type) != ARP_OPERATION_REPLY ||
memcmp(&reply->sender_hardware_address, &mac, sizeof(mac_address_t)) ||
memcmp(&reply->sender_protocol_address, &ip, sizeof(ip_address_t)) ||
memcmp(&reply->target_hardware_address, &net_mac, sizeof(mac_address_t)) ||
memcmp(&reply->target_protocol_address, &net_ip, sizeof(ip_address_t))) {
// Unexpected reply
snprintf(msg, msgmax, "ARP module sent an unexpected reply");
return TEST_FAILED;
}
return TEST_PASSED;
}
test_result_t test_arp_bb_B(char *msg, size_t msgmax)
{
// Addresses of the packets that will be sent towards
// the ARP module
const char net_ip_str[] = "10.0.0.5";
const char net_mac_str[] = "00:34:56:34:f5:4f";
// Addresses of the ARP module
const char ip_str[] = "10.0.0.4";
const char mac_str[] = "56:34:f5:4d:4f:44";
// Parse the addresses to binary form
ip_address_t ip, net_ip;
mac_address_t mac, net_mac;
if (!parse_mac(mac_str, sizeof(mac_str)-1, &mac) ||
!parse_ip(ip_str, &ip) ||
!parse_mac(net_mac_str, sizeof(net_mac_str)-1, &net_mac) ||
!parse_ip(net_ip_str, &net_ip)) {
snprintf(msg, msgmax, "Couldn't parse IP and MAC strings");
return TEST_ABORTED;
}
// Set up the module with the output queue
arp_state_t state;
output_queue_t oq = {.state=&state, .count=0, .oflow=0}; // Buffer where replies and requests will be stored
// by the ARP module
arp_init(&state, ip, mac, &oq, send_arp_packet_callback);
arp_change_output_buffer(&state, oq.queue, sizeof(arp_packet_t));
// Build the request
arp_packet_t request = {
.hardware_type = cpu_to_net_u16(ARP_HARDWARE_ETHERNET)+1, // Some value other than ETHERNET
.protocol_type = cpu_to_net_u16(ARP_PROTOCOL_IP),
.hardware_len = 6,
.protocol_len = 4,
.operation_type = cpu_to_net_u16(ARP_OPERATION_REQUEST),
.sender_hardware_address = net_mac,
.sender_protocol_address = net_ip,
.target_hardware_address = MAC_ZERO,
.target_protocol_address = ip,
};
// Send the request
arp_process_result_t res;
res = arp_process_packet(&state, &request, sizeof(arp_packet_t));
switch (res) {
case ARP_PROCESS_RESULT_HWARENOTSUPP:
break;
case ARP_PROCESS_RESULT_PROTONOTSUPP:
case ARP_PROCESS_RESULT_INVALID:
snprintf(msg, msgmax, "ARP module couldn't process request");
return TEST_FAILED;
case ARP_PROCESS_RESULT_OK:
snprintf(msg, msgmax, "ARP module processed a request for an hardware type it didn't support");
return TEST_FAILED;
}
if (oq.count > 0) {
// Sent replies
snprintf(msg, msgmax, "ARP module replied even though it failed to process the request");
return TEST_FAILED;
}
return TEST_PASSED;
}
test_result_t test_arp_bb_C(char *msg, size_t msgmax)
{
// Addresses of the packets that will be sent towards
// the ARP module
const char net_ip_str[] = "10.0.0.5";
const char net_mac_str[] = "00:34:56:34:f5:4f";
// Addresses of the ARP module
const char ip_str[] = "10.0.0.4";
const char mac_str[] = "56:34:f5:4d:4f:44";
// Parse the addresses to binary form
ip_address_t ip, net_ip;
mac_address_t mac, net_mac;
if (!parse_mac(mac_str, sizeof(mac_str)-1, &mac) ||
!parse_ip(ip_str, &ip) ||
!parse_mac(net_mac_str, sizeof(net_mac_str)-1, &net_mac) ||
!parse_ip(net_ip_str, &net_ip)) {
snprintf(msg, msgmax, "Couldn't parse IP and MAC strings");
return TEST_ABORTED;
}
// Set up the module with the output queue
arp_state_t state;
output_queue_t oq = {.state=&state, .count=0, .oflow=0}; // Buffer where replies and requests will be stored
// by the ARP module
arp_init(&state, ip, mac, &oq, send_arp_packet_callback);
arp_change_output_buffer(&state, oq.queue, sizeof(arp_packet_t));
// Build the request
arp_packet_t request = {
.hardware_type = cpu_to_net_u16(ARP_HARDWARE_ETHERNET),
.protocol_type = cpu_to_net_u16(ARP_PROTOCOL_IP)+1, // Some value other than IP
.hardware_len = 6,
.protocol_len = 4,
.operation_type = cpu_to_net_u16(ARP_OPERATION_REQUEST),
.sender_hardware_address = net_mac,
.sender_protocol_address = net_ip,
.target_hardware_address = MAC_ZERO,
.target_protocol_address = ip,
};
// Send the request
arp_process_result_t res;
res = arp_process_packet(&state, &request, sizeof(arp_packet_t));
switch (res) {
case ARP_PROCESS_RESULT_PROTONOTSUPP:
break;
case ARP_PROCESS_RESULT_HWARENOTSUPP:
case ARP_PROCESS_RESULT_INVALID:
snprintf(msg, msgmax, "ARP module couldn't process request");
return TEST_FAILED;
case ARP_PROCESS_RESULT_OK:
snprintf(msg, msgmax, "ARP module processed a request for a protocol type it didn't support");
return TEST_FAILED;
}
if (oq.count > 0) {
// Sent replies
snprintf(msg, msgmax, "ARP module replied even though it failed to process the request");
return TEST_FAILED;
}
return TEST_PASSED;
}
test_result_t test_arp_bb_D(char *msg, size_t msgmax)
{
// Addresses of the packets that will be sent towards
// the ARP module
const char net_ip_str[] = "10.0.0.5";
const char net_mac_str[] = "00:34:56:34:f5:4f";
// Addresses of the ARP module
const char ip_str[] = "10.0.0.4";
const char mac_str[] = "56:34:f5:4d:4f:44";
// Parse the addresses to binary form
ip_address_t ip, net_ip;
mac_address_t mac, net_mac;
if (!parse_mac(mac_str, sizeof(mac_str)-1, &mac) ||
!parse_ip(ip_str, &ip) ||
!parse_mac(net_mac_str, sizeof(net_mac_str)-1, &net_mac) ||
!parse_ip(net_ip_str, &net_ip)) {
snprintf(msg, msgmax, "Couldn't parse IP and MAC strings");
return TEST_ABORTED;
}
// Set up the module with the output queue
arp_state_t state;
output_queue_t oq = {.state=&state, .count=0, .oflow=0}; // Buffer where replies and requests will be stored
// by the ARP module
arp_init(&state, ip, mac, &oq, send_arp_packet_callback);
arp_change_output_buffer(&state, oq.queue, sizeof(arp_packet_t));
// Build the request
arp_packet_t request = {
.hardware_type = cpu_to_net_u16(ARP_HARDWARE_ETHERNET),
.protocol_type = cpu_to_net_u16(ARP_PROTOCOL_IP),
.hardware_len = 6+1, // Something other than the correct length
.protocol_len = 4,
.operation_type = cpu_to_net_u16(ARP_OPERATION_REQUEST),
.sender_hardware_address = net_mac,
.sender_protocol_address = net_ip,
.target_hardware_address = MAC_ZERO,
.target_protocol_address = ip,
};
// Send the request
arp_process_result_t res;
res = arp_process_packet(&state, &request, sizeof(arp_packet_t));
switch (res) {
case ARP_PROCESS_RESULT_INVALID:
break;
case ARP_PROCESS_RESULT_HWARENOTSUPP:
case ARP_PROCESS_RESULT_PROTONOTSUPP:
snprintf(msg, msgmax, "ARP module couldn't process request");
return TEST_FAILED;
case ARP_PROCESS_RESULT_OK:
snprintf(msg, msgmax, "ARP module processed a request for an invalid hardware address length");
return TEST_FAILED;
}
if (oq.count > 0) {
// Sent replies
snprintf(msg, msgmax, "ARP module replied even though it failed to process the request");
return TEST_FAILED;
}
return TEST_PASSED;
}
test_result_t test_arp_bb_E(char *msg, size_t msgmax)
{
// Addresses of the packets that will be sent towards
// the ARP module
const char net_ip_str[] = "10.0.0.5";
const char net_mac_str[] = "00:34:56:34:f5:4f";
// Addresses of the ARP module
const char ip_str[] = "10.0.0.4";
const char mac_str[] = "56:34:f5:4d:4f:44";
// Parse the addresses to binary form
ip_address_t ip, net_ip;
mac_address_t mac, net_mac;
if (!parse_mac(mac_str, sizeof(mac_str)-1, &mac) ||
!parse_ip(ip_str, &ip) ||
!parse_mac(net_mac_str, sizeof(net_mac_str)-1, &net_mac) ||
!parse_ip(net_ip_str, &net_ip)) {
snprintf(msg, msgmax, "Couldn't parse IP and MAC strings");
return TEST_ABORTED;
}
// Set up the module with the output queue
arp_state_t state;
output_queue_t oq = {.state=&state, .count=0, .oflow=0}; // Buffer where replies and requests will be stored
// by the ARP module
arp_init(&state, ip, mac, &oq, send_arp_packet_callback);
arp_change_output_buffer(&state, oq.queue, sizeof(arp_packet_t));
// Build the request
arp_packet_t request = {
.hardware_type = cpu_to_net_u16(ARP_HARDWARE_ETHERNET),
.protocol_type = cpu_to_net_u16(ARP_PROTOCOL_IP),
.hardware_len = 6,
.protocol_len = 4+1, // Something other than the correct length
.operation_type = cpu_to_net_u16(ARP_OPERATION_REQUEST),
.sender_hardware_address = net_mac,
.sender_protocol_address = net_ip,
.target_hardware_address = MAC_ZERO,
.target_protocol_address = ip,
};
// Send the request
arp_process_result_t res;
res = arp_process_packet(&state, &request, sizeof(arp_packet_t));
switch (res) {
case ARP_PROCESS_RESULT_INVALID:
break;
case ARP_PROCESS_RESULT_HWARENOTSUPP:
case ARP_PROCESS_RESULT_PROTONOTSUPP:
snprintf(msg, msgmax, "ARP module couldn't process request");
return TEST_FAILED;
case ARP_PROCESS_RESULT_OK:
snprintf(msg, msgmax, "ARP module processed a request for an invalid protocol address length");
return TEST_FAILED;
}
if (oq.count > 0) {
// Sent replies
snprintf(msg, msgmax, "ARP module replied even though it failed to process the request");
return TEST_FAILED;
}
return TEST_PASSED;
}
int main(void)
{
void *tests[] = {
test_arp_bb_A,
test_arp_bb_B,
test_arp_bb_C,
test_arp_bb_D,
test_arp_bb_E,
};
char msg[256];
for (size_t i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) {
test_result_t (*test_fn)(char*, size_t) = tests[i];
switch (test_fn(msg, sizeof(msg))) {
case TEST_PASSED: fprintf(stdout, "PASSED\n"); break;
case TEST_FAILED: fprintf(stdout, "FAILED: %s\n", msg); break;
case TEST_ABORTED: fprintf(stdout, "ABORTED: %s\n", msg); break;
}
}
return 0;
}