diff --git a/src/endian.c b/src/endian.c index 1e3c67c..04ecd07 100644 --- a/src/endian.c +++ b/src/endian.c @@ -1,7 +1,6 @@ -#include #include "endian.h" -static bool cpu_is_little_endian(void) +bool cpu_is_little_endian(void) { uint16_t x = 1; return *((uint8_t*) &x); diff --git a/src/endian.h b/src/endian.h index d0e99bb..f916808 100644 --- a/src/endian.h +++ b/src/endian.h @@ -1,5 +1,7 @@ #include +#include +bool cpu_is_little_endian(void); uint16_t net_to_cpu_u16(uint16_t n); uint32_t net_to_cpu_u32(uint32_t n); uint16_t cpu_to_net_u16(uint16_t n); diff --git a/src/ip.c b/src/ip.c index e205c34..cc40997 100644 --- a/src/ip.c +++ b/src/ip.c @@ -70,8 +70,16 @@ static void send_icmp_packet(void *data, ip_address_t ip, size_t len) // The data was written in the output buffer ip_packet_t *packet = ip_state->output_ptr; // This changes every iteration - packet->version = 4; - packet->header_length = 5; + + int version = 4; + int header_length = 5; + if (cpu_is_little_endian()) { + packet->header_length_or_version1 = header_length; + packet->header_length_or_version2 = version; + } else { + packet->header_length_or_version1 = version; + packet->header_length_or_version2 = header_length; + } packet->type_of_service = 0; // ??? packet->total_length = cpu_to_net_u16(sizeof(ip_packet_t) + len); packet->id = ip_state->next_id++; @@ -82,7 +90,7 @@ static void send_icmp_packet(void *data, ip_address_t ip, size_t len) packet->src_ip = ip_state->ip; packet->dst_ip = ip; - packet->checksum = calculate_checksum_ip((uint16_t*) packet, 4 * packet->header_length); + packet->checksum = calculate_checksum_ip((uint16_t*) packet, 4 * header_length); ip_state->send(ip_state->send_data, ip, sizeof(ip_packet_t) + len); } @@ -163,8 +171,16 @@ int ip_send_2(ip_state_t *state, ip_protocol_t protocol, ip_address_t dst, size_t considered_payload = MIN(current_payload_limit, remaining_payload); ip_packet_t *packet = state->output_ptr; // This changes every iteration - packet->version = 4; - packet->header_length = 5; + + int version = 4; + int header_length = 5; + if (cpu_is_little_endian()) { + packet->header_length_or_version1 = header_length; + packet->header_length_or_version2 = version; + } else { + packet->header_length_or_version1 = version; + packet->header_length_or_version2 = header_length; + } packet->type_of_service = 0; // ??? packet->total_length = cpu_to_net_u16(sizeof(ip_packet_t) + considered_payload); packet->id = state->next_id++; @@ -184,7 +200,7 @@ int ip_send_2(ip_state_t *state, ip_protocol_t protocol, ip_address_t dst, copied_slices++; } - packet->checksum = calculate_checksum_ip((uint16_t*) packet, 4 * packet->header_length); + packet->checksum = calculate_checksum_ip((uint16_t*) packet, 4 * header_length); // Sending updates the [state->output_ptr] and [state->output_len] state->send(state->send_data, dst, sizeof(ip_packet_t) + considered_payload); @@ -202,12 +218,23 @@ void ip_process_packet(ip_state_t *ip_state, const void *packet, size_t len) const ip_packet_t *packet2 = packet; - if (packet2->version != 4 || packet2->header_length < 5) { - IP_DEBUG_LOG("Only supported IPv4 (received %d) with no options", packet2->version); + int version; + int header_length; + + if (cpu_is_little_endian()) { + header_length = packet2->header_length_or_version1; + version = packet2->header_length_or_version2; + } else { + version = packet2->header_length_or_version1; + header_length = packet2->header_length_or_version2; + } + + if (version != 4 || header_length < 5) { + IP_DEBUG_LOG("Only supported IPv4 (received %d) with no options", version); return; } - size_t option_count = packet2->header_length - sizeof(ip_packet_t)/4; + size_t option_count = header_length - sizeof(ip_packet_t)/4; if (option_count > 0) { #warning "TODO: Handle IP options" return; @@ -218,7 +245,7 @@ void ip_process_packet(ip_state_t *ip_state, const void *packet, size_t len) return; } - if (calculate_checksum_ip((uint16_t*) packet2, 4 * packet2->header_length)) { + if (calculate_checksum_ip((uint16_t*) packet2, 4 * header_length)) { IP_DEBUG_LOG("Dropping IP packet with invalid checksum"); return; } diff --git a/src/ip.h b/src/ip.h index 2b639d2..a831ea1 100644 --- a/src/ip.h +++ b/src/ip.h @@ -7,13 +7,8 @@ #define IP_PLUGGED_PROTOCOLS_MAX 4 typedef struct { -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - uint8_t header_length: 4; - uint8_t version: 4; -#else - uint8_t version: 4; - uint8_t header_length: 4; -#endif + uint8_t header_length_or_version1: 4; // Header length when little endian + uint8_t header_length_or_version2: 4; // Header length when big endian uint8_t type_of_service; uint16_t total_length; uint16_t id; diff --git a/src/tcp.c b/src/tcp.c index 7716c9f..947fe1c 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -10,6 +10,8 @@ #define TCP_DEBUG_LOG(...) #endif +#define SEGMENT_OFFSET(seg) (cpu_is_little_endian() ? (seg)->offset2 : (seg)->offset1) + void tcp_init(tcp_state_t *tcp_state, ip_address_t ip, tcp_callbacks_t callbacks) { tcp_state->ip = ip; @@ -134,7 +136,7 @@ calculate_checksum(const slice_list_t *slices, size_t num_slices) } } - return cpu_to_net_u32(~sum); + return cpu_to_net_u16(~sum); } static void emit_segment(tcp_connection_t *connection, bool ack, bool syn, size_t payload) @@ -158,15 +160,16 @@ static void emit_segment(tcp_connection_t *connection, bool ack, bool syn, size_ //if (payload_being_sent > 0) // seq_no++; + int offset = 5; // No options tcp_segment_t header = { .src_port = cpu_to_net_u16(listener->port), .dst_port = cpu_to_net_u16(connection->peer_port), .flags = flags, .seq_no = cpu_to_net_u32(seq_no), .ack_no = cpu_to_net_u32(ack_no), - .offset = 5, // No options - .unused = 0, - .window = cpu_to_net_u32(connection->rcv_wnd), + .offset1 = cpu_is_little_endian() ? 0 : offset, + .offset2 = cpu_is_little_endian() ? offset : 0, + .window = cpu_to_net_u16(connection->rcv_wnd), // Why is a 32 bit integer being backed into a 16 bit? .checksum = 0, // Will be calculated later .urgent_pointer = 0, }; @@ -176,7 +179,7 @@ static void emit_segment(tcp_connection_t *connection, bool ack, bool syn, size_ .dst_addr = connection->peer_ip, .reserved = 0, .protocol = 6, // TCP - .tcp_length = cpu_to_net_u32(total_segment_size), + .tcp_length = cpu_to_net_u16(total_segment_size), }; header.checksum = calculate_checksum((slice_list_t[]) { @@ -250,7 +253,17 @@ find_connection_associated_to_listener(tcp_listener_t *listener, connection = connection->next; } } - + if (connection) { + // established=true + } else { + // established=false + connection = listener->non_established_list; + while (connection) { + if (connection->peer_port == peer_port && connection->peer_ip == peer_ip) + break; + connection = connection->next; + } + } return connection; } @@ -286,7 +299,7 @@ void tcp_process_segment(tcp_state_t *state, ip_address_t sender, TCP_DEBUG_LOG("Received TCP segment"); assert(len >= sizeof(tcp_segment_t)); - size_t data_offset = segment->offset * sizeof(uint32_t); // Length (in bytes) of the TCP header, + size_t data_offset = SEGMENT_OFFSET(segment) * sizeof(uint32_t); // Length (in bytes) of the TCP header, // comprehensive of options. size_t options_len = data_offset - sizeof(tcp_segment_t); // The number of bytes of the options is diff --git a/src/tcp.h b/src/tcp.h index a7b2140..3907e88 100644 --- a/src/tcp.h +++ b/src/tcp.h @@ -21,19 +21,15 @@ typedef struct { uint16_t dst_port; uint32_t seq_no; uint32_t ack_no; -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - uint8_t unused: 4; - uint8_t offset: 4; -#else - uint8_t offset: 4; - uint8_t unused: 4; -#endif + uint8_t offset1: 4; // When CPU is big endian + uint8_t offset2: 4; // When CPU is little endian uint8_t flags; uint16_t window; uint16_t checksum; uint16_t urgent_pointer; char payload[]; } tcp_segment_t; +static_assert(sizeof(tcp_segment_t) == 20); typedef struct tcp_connection_t tcp_connection_t; typedef struct tcp_listener_t tcp_listener_t;