fixed i forgot about but seem to work
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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,19 +606,23 @@ 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;
|
||||
packet->hardware_type = cpu_to_net_u16(ARP_HARDWARE_ETHERNET);
|
||||
packet->protocol_type = cpu_to_net_u16(ARP_PROTOCOL_IP);
|
||||
packet->hardware_len = 6;
|
||||
packet->protocol_len = 4;
|
||||
packet->operation_type = cpu_to_net_u16(ARP_OPERATION_REQUEST);
|
||||
packet->sender_hardware_address = state->self_mac;
|
||||
packet->sender_protocol_address = state->self_ip;
|
||||
packet->target_hardware_address = MAC_ZERO; // This is what we're trying to find
|
||||
packet->target_protocol_address = ip;
|
||||
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;
|
||||
packet->protocol_len = 4;
|
||||
packet->operation_type = cpu_to_net_u16(ARP_OPERATION_REQUEST);
|
||||
packet->sender_hardware_address = state->self_mac;
|
||||
packet->sender_protocol_address = state->self_ip;
|
||||
packet->target_hardware_address = MAC_ZERO; // This is what we're trying to find
|
||||
packet->target_protocol_address = ip;
|
||||
|
||||
ARP_DEBUG_LOG("Sending out ARP request to resolve MAC");
|
||||
ARP_DEBUG_LOG("Sending out ARP request to resolve MAC");
|
||||
|
||||
state->send(state->send_data, MAC_BROADCAST);
|
||||
state->send(state->send_data, MAC_BROADCAST);
|
||||
} else {
|
||||
ARP_DEBUG_LOG("Couldn't send ARP request because no output buffer was provided");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -83,7 +96,7 @@ typedef struct {
|
||||
arp_pending_request_t *pending_request_free_list;
|
||||
arp_pending_request_t *pending_request_used_list;
|
||||
arp_pending_request_t *pending_request_used_tail;
|
||||
arp_pending_request_t pending_request_pool[ARP_MAX_PENDING_REQUESTS];
|
||||
arp_pending_request_t pending_request_pool[ARP_MAX_PENDING_REQUESTS];
|
||||
} arp_state_t;
|
||||
|
||||
typedef enum {
|
||||
@@ -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
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
@@ -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 ]
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user