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
+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;
}