This commit is contained in:
Francesco Cozzuto
2023-04-21 09:46:44 +02:00
parent 092ba2d1ad
commit 43ee04a2db
9 changed files with 510 additions and 47 deletions
+5
View File
@@ -15,6 +15,11 @@ static_assert(sizeof(ip_address_t) == 4);
#define MAC_ZERO (mac_address_t) {.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}
#define MAC_BROADCAST (mac_address_t) {.data = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}
typedef struct {
const void *src;
size_t len;
} slice_list_t;
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
+27 -6
View File
@@ -120,11 +120,26 @@ void ip_seconds_passed(ip_state_t *state, size_t seconds)
(void) seconds;
}
int ip_send(ip_state_t *state, ip_protocol_t protocol, ip_address_t dst, bool no_fragm, const void *src, size_t len)
int ip_send(ip_state_t *state, ip_protocol_t protocol,
ip_address_t dst, bool no_fragm,
const void *src, size_t len)
{
const slice_list_t slices[] = {
{src, len}
};
return ip_send_2(state, protocol, dst, no_fragm, slices, 1);
}
int ip_send_2(ip_state_t *state, ip_protocol_t protocol, ip_address_t dst,
bool no_fragm, const slice_list_t *slices, size_t num_slices)
{
size_t total_len = 0;
for (size_t i = 0; i < num_slices; i++)
total_len += slices[i].len;
size_t managed_payload = 0;
while (managed_payload < len && (managed_payload == 0 || !no_fragm)) {
while (managed_payload < total_len && (managed_payload == 0 || !no_fragm)) {
if (state->output_ptr == NULL) {
// Lower layers of the network stack didn't specify an output
@@ -144,7 +159,7 @@ int ip_send(ip_state_t *state, ip_protocol_t protocol, ip_address_t dst, bool no
return -1;
size_t current_payload_limit = state->output_max - sizeof(ip_packet_t);
size_t remaining_payload = len - managed_payload;
size_t remaining_payload = total_len - managed_payload;
size_t considered_payload = MIN(current_payload_limit, remaining_payload);
ip_packet_t *packet = state->output_ptr; // This changes every iteration
@@ -159,9 +174,15 @@ int ip_send(ip_state_t *state, ip_protocol_t protocol, ip_address_t dst, bool no
packet->checksum = 0; // Temporary value
packet->src_ip = state->ip;
packet->dst_ip = dst;
memcpy(packet->payload,
src + managed_payload,
considered_payload);
size_t copied_bytes = 0;
size_t copied_slices = 0;
while (copied_bytes < considered_payload) {
size_t copying = MIN(slices[copied_slices].len, considered_payload - copied_bytes);
memcpy(packet->payload + copied_bytes, slices[copied_slices].src, copying);
copied_bytes += copying;
copied_slices++;
}
packet->checksum = calculate_checksum_ip((uint16_t*) packet, 4 * packet->header_length);
+1
View File
@@ -61,5 +61,6 @@ void ip_change_output_buffer(ip_state_t *state, void *ptr, size_t max);
void ip_init(ip_state_t *state, ip_address_t ip, void *send_data, void (*send)(void*, ip_address_t, size_t));
void ip_free(ip_state_t *state);
int ip_send(ip_state_t *state, ip_protocol_t protocol, ip_address_t dst, bool no_fragm, const void *src, size_t len);
int ip_send_2(ip_state_t *state, ip_protocol_t protocol, ip_address_t dst, bool no_fragm, const slice_list_t *slices, size_t num_slices);
void ip_process_packet(ip_state_t *state, const void *packet, size_t len);
bool ip_plug_protocol(ip_state_t *ip_state, uint8_t protocol, void *data, void (*process_packet)(void *data, ip_address_t sender, const void *packet, size_t len));
+4 -3
View File
@@ -160,11 +160,12 @@ static void send_arp_packet(void *data, mac_address_t dst)
mtcp->used_buffer->used = 0;
}
static int send_tcp_segment(void *data, ip_address_t dst,
const void *str, size_t len)
static int send_tcp_segment(void *data, ip_address_t ip,
const slice_list_t *slices,
size_t num_slices)
{
microtcp_t *mtcp = data;
return ip_send(&mtcp->ip_state, IP_PROTOCOL_TCP, dst, true, str, len);
return ip_send_2(&mtcp->ip_state, IP_PROTOCOL_TCP, ip, true, slices, num_slices);
}
static void move_wait_buffer_to_free_list(buffer_t *buffer)
+83 -32
View File
@@ -10,12 +10,6 @@
#define TCP_DEBUG_LOG(...)
#endif
static int tcp_send(tcp_state_t *tcp_state, ip_address_t ip,
const void *src, size_t len)
{
return tcp_state->callbacks.send(tcp_state->callbacks.data, ip, src, len);
}
void tcp_init(tcp_state_t *tcp_state, ip_address_t ip, tcp_callbacks_t callbacks)
{
tcp_state->ip = ip;
@@ -47,6 +41,10 @@ void tcp_seconds_passed(tcp_state_t *state, size_t seconds)
(void) seconds;
}
typedef enum {
TCP_CONNECTION_
} tcp_connection_state;
static tcp_connection_t*
connection_create_waiting_for_ack(tcp_listener_t *listener,
uint32_t seq_no, uint32_t ack_no,
@@ -133,7 +131,9 @@ static tcp_connection_t *find_connection(tcp_connection_t *list, ip_address_t pe
return NULL;
}
static connection_state_t find_connection_associated_to(tcp_listener_t *listener, ip_address_t peer_ip, uint16_t peer_port, tcp_connection_t **connection)
static connection_state_t
find_connection_associated_to(tcp_listener_t *listener, ip_address_t peer_ip,
uint16_t peer_port, tcp_connection_t **connection)
{
tcp_connection_t *connection2 = find_connection(listener->connections, peer_ip, peer_port);
if (connection2) {
@@ -175,25 +175,21 @@ typedef struct {
} tcp_pseudoheader_t;
static uint16_t
calculate_checksum_tcp(const void *a, const void *b,
size_t a_len, size_t b_len)
calculate_checksum(const slice_list_t *slices, size_t num_slices)
{
assert((a_len & 1) == 0
&& (b_len & 1) == 0);
const uint16_t *a2 = a;
const uint16_t *b2 = b;
uint32_t sum = 0xffff;
for (size_t i = 0; i < a_len/2; i++) {
sum += ntohs(a2[i]);
if (sum > 0xffff)
sum -= 0xffff;
}
for (size_t i = 0; i < b_len/2; i++) {
sum += ntohs(b2[i]);
if (sum > 0xffff)
sum -= 0xffff;
for (size_t slice_idx = 0; slice_idx < num_slices; slice_idx++) {
assert((slices[slice_idx].len & 1) == 0);
const uint16_t *src = slices[slice_idx].src;
const size_t len = slices[slice_idx].len;
for (size_t i = 0; i < len/2; i++) {
sum += ntohs(src[i]);
if (sum > 0xffff)
sum -= 0xffff;
}
}
return htons(~sum);
@@ -252,7 +248,7 @@ static void emit_segment(tcp_connection_t *connection, bool ack, bool syn, size_
//if (payload_being_sent > 0)
// seq_no++;
connection->out_header = (tcp_segment_t) {
tcp_segment_t header = {
.src_port = htons(listener->port),
.dst_port = htons(connection->peer_port),
.flags = flags,
@@ -273,10 +269,17 @@ static void emit_segment(tcp_connection_t *connection, bool ack, bool syn, size_
.tcp_length = htons(total_segment_size),
};
connection->out_header.checksum = calculate_checksum_tcp(&pseudo_header, &connection->out_header, sizeof(pseudo_header), total_segment_size);
header.checksum = calculate_checksum((slice_list_t[]) {
{&pseudo_header, sizeof(tcp_pseudoheader_t)},
{&header, sizeof(tcp_segment_t)},
{connection->out_buffer, connection->snd_wnd},
}, 3);
int result = state->callbacks.send(state->callbacks.data, connection->peer_ip, (slice_list_t[]) {
{&header, sizeof(tcp_segment_t)},
{connection->out_buffer, payload_being_sent},
}, 2);
int result = tcp_send(state, connection->peer_ip, &connection->out_header, total_segment_size);
if (result < 0) {
// It wasn't possible to send out bytes. We'll try again later!
} else {
@@ -449,6 +452,7 @@ tcp_listener_create(tcp_state_t *state, uint16_t port, void *callback_data,
listener->port = port;
listener->connections = NULL;
listener->connections_waiting_for_ack = NULL;
listener->connections_waiting_for_fin = NULL;
listener->connections_waiting_for_accept_head = NULL;
listener->connections_waiting_for_accept_tail = NULL;
listener->callback_data = callback_data;
@@ -533,13 +537,18 @@ void tcp_connection_destroy(tcp_connection_t *connection)
// NOTE: This can only be called when the
// connection was accepted.
// Make sure the connection was first finished
// by being moved from the idle list to the
// waiting-for-fin list.
tcp_connection_finish(connection);
tcp_listener_t *listener = connection->listener;
// Pop connection from the idle connection list
// Pop connection from the waiting-for-fin list
if (connection->prev)
connection->prev->next = connection->next;
else
listener->connections = connection->next;
listener->connections_waiting_for_fin = connection->next;
// Push it into the free connection list
tcp_state_t *state = listener->state;
@@ -583,7 +592,49 @@ append_to_output_buffer(tcp_connection_t *connection,
size_t tcp_connection_send(tcp_connection_t *connection, const void *src, size_t len)
{
size_t num = append_to_output_buffer(connection, src, len);
emit_segment(connection, false, false, SIZE_MAX);
size_t num;
if (connection->read_only)
num = 0;
else {
num = append_to_output_buffer(connection, src, len);
emit_segment(connection, false, false, SIZE_MAX);
}
return num;
}
void tcp_connection_finish(tcp_connection_t *connection)
{
if (!connection->read_only) {
// Move connection from idle list to
// waiting-for-fin list
tcp_listener_t *listener = connection->listener;
// Pop it from the idle list
{
if (connection->prev)
connection->prev->next = connection->next;
else
listener->connections = connection->next;
if (connection->next)
connection->next->prev = connection->prev;
connection->prev = NULL;
connection->next = NULL;
}
#warning "The FIN segment should be sent here"
// Push it to the waiting-for-fin list
{
connection->prev = NULL;
connection->next = listener->connections_waiting_for_fin;
listener->connections_waiting_for_fin = connection;
}
// Now mark the connection as read-only
connection->read_only = true;
}
}
+9 -6
View File
@@ -47,6 +47,8 @@ struct tcp_listener_t {
tcp_connection_t *connections_waiting_for_ack;
tcp_connection_t *connections_waiting_for_accept_head;
tcp_connection_t *connections_waiting_for_accept_tail;
tcp_connection_t *connections_waiting_for_fin;
void (*callback_ready_to_accept)(void*);
void *callback_data;
};
@@ -60,6 +62,8 @@ struct tcp_connection_t {
void (*callback_ready_to_recv)(void*);
void (*callback_ready_to_send)(void*);
bool read_only;
ip_address_t peer_ip; // Network byte order
uint16_t peer_port; // CPU byte order
@@ -92,16 +96,14 @@ struct tcp_connection_t {
uint32_t snd_una; // SND.UNA from RFC 793
// It's the sequence number of the last
// byte sent and acknowledged by the peer.
tcp_segment_t out_header; // There must be no padding between
char out_buffer[TCP_OUTPUT_BUFFER_SIZE]; // these two
char in_buffer[TCP_INPUT_BUFFER_SIZE];
char out_buffer[TCP_OUTPUT_BUFFER_SIZE];
char in_buffer[TCP_INPUT_BUFFER_SIZE];
};
static_assert(offsetof(tcp_connection_t, out_buffer) == offsetof(tcp_connection_t, out_header) + sizeof(tcp_segment_t));
typedef struct {
void *data;
int (*send)(void *data, ip_address_t ip, const void *src, size_t len);
int (*send)(void *data, ip_address_t ip, const slice_list_t *slices, size_t num_slices);
} tcp_callbacks_t;
struct tcp_state_t {
@@ -123,5 +125,6 @@ tcp_listener_t *tcp_listener_create(tcp_state_t *state, uint16_t port, void *d
void tcp_listener_destroy(tcp_listener_t *listener);
tcp_connection_t *tcp_listener_accept(tcp_listener_t *listener, void *callback_data, void (*callback_ready_to_recv)(void*), void (*callback_ready_to_send)(void*));
void tcp_connection_destroy(tcp_connection_t *connection);
void tcp_connection_finish(tcp_connection_t *connection);
size_t tcp_connection_recv(tcp_connection_t *connection, void *dst, size_t len);
size_t tcp_connection_send(tcp_connection_t *connection, const void *src, size_t len);