diff options
author | Anton Kling <anton@kling.gg> | 2024-06-22 14:34:21 +0200 |
---|---|---|
committer | Anton Kling <anton@kling.gg> | 2024-06-22 14:34:21 +0200 |
commit | 01b88a7bf9fb4c78bd632bfccb06f3d320a21fd5 (patch) | |
tree | 20d9a6dcc155e7c8b6e067c6ba6d7b42df4365fd | |
parent | af313dec6b7698b6f948b97669aa7be91717a451 (diff) |
Kernel stuff
-rw-r--r-- | kernel/drivers/pit.c | 2 | ||||
-rw-r--r-- | kernel/drivers/rtl8139.c | 19 | ||||
-rw-r--r-- | kernel/fs/vfs.c | 7 | ||||
-rw-r--r-- | kernel/init/kernel.c | 2 | ||||
-rw-r--r-- | kernel/network/ethernet.c | 4 | ||||
-rw-r--r-- | kernel/network/tcp.c | 337 | ||||
-rw-r--r-- | kernel/network/tcp.h | 28 | ||||
-rw-r--r-- | kernel/network/udp.c | 3 | ||||
-rw-r--r-- | kernel/sched/scheduler.c | 20 | ||||
-rw-r--r-- | kernel/sched/scheduler.h | 2 | ||||
-rw-r--r-- | kernel/socket.c | 204 | ||||
-rw-r--r-- | kernel/socket.h | 29 |
12 files changed, 309 insertions, 348 deletions
diff --git a/kernel/drivers/pit.c b/kernel/drivers/pit.c index eb98119..b938de4 100644 --- a/kernel/drivers/pit.c +++ b/kernel/drivers/pit.c @@ -44,7 +44,7 @@ void set_pit_count(u16 _hertz) { } void int_clock(reg_t *regs) { - clock_num_ms_ticks += 10; + clock_num_ms_ticks += 5; switch_counter++; if (switch_counter >= hertz) { EOI(0x20); diff --git a/kernel/drivers/rtl8139.c b/kernel/drivers/rtl8139.c index c0aa0b2..74d7c05 100644 --- a/kernel/drivers/rtl8139.c +++ b/kernel/drivers/rtl8139.c @@ -3,6 +3,7 @@ #include <cpu/io.h> #include <drivers/pci.h> #include <drivers/rtl8139.h> +#include <interrupts.h> #include <mmu.h> #include <network/arp.h> #include <network/ethernet.h> @@ -47,18 +48,18 @@ u32 current_packet_read = 0; void handle_packet(void) { assert(sizeof(struct _INT_PACKET_HEADER) == sizeof(u16)); - for (int i = 0; 0 == (inb(rtl8139.gen.base_mem_io + 0x37) & 1); i++) { + for (; 0 == (inb(rtl8139.gen.base_mem_io + 0x37) & 1);) { u16 *buf = (u16 *)(device_buffer + current_packet_read); struct PACKET_HEADER packet_header; packet_header.raw = *buf; if (packet_header.data.FAE) { - return; + break; } if (packet_header.data.CRC) { - return; + break; } if (!packet_header.data.ROK) { - return; + break; } u16 packet_length = *(buf + 1); assert(packet_length <= 2048); @@ -90,6 +91,7 @@ void handle_packet(void) { } void rtl8139_handler(void *regs) { + disable_interrupts(); (void)regs; u16 status = inw(rtl8139.gen.base_mem_io + 0x3e); @@ -110,16 +112,7 @@ void rtl8139_send_data(u8 *data, u16 data_size) { data_size -= 0x1000; return rtl8139_send_data(data, data_size); } - // ipc_write(0, data, data_size); const struct PCI_DEVICE *device = &rtl8139; - // FIXME: It should block or fail if there is too little space for the - // buffer - if (data_size > 0x1000) { - rtl8139_send_data(data, 0x1000); - data += 0x1000; - data_size -= 0x1000; - return rtl8139_send_data(data, data_size); - } if (send_buffers_loop > 3) { send_buffers_loop = 0; } diff --git a/kernel/fs/vfs.c b/kernel/fs/vfs.c index 666dfc9..7c97cb2 100644 --- a/kernel/fs/vfs.c +++ b/kernel/fs/vfs.c @@ -300,13 +300,12 @@ int vfs_close_process(process_t *p, int fd) { assert(relist_remove(&p->file_descriptors, fd)); // If no references left then free the contents if (0 == fd_ptr->reference_count) { - if (fd_ptr->inode->close) { - fd_ptr->inode->close(fd_ptr); - } - assert(0 < fd_ptr->inode->ref); fd_ptr->inode->ref--; if (0 >= fd_ptr->inode->ref) { + if (fd_ptr->inode->close) { + fd_ptr->inode->close(fd_ptr); + } kfree(fd_ptr->inode); } kfree(fd_ptr); diff --git a/kernel/init/kernel.c b/kernel/init/kernel.c index bbc93ea..83f4af8 100644 --- a/kernel/init/kernel.c +++ b/kernel/init/kernel.c @@ -70,7 +70,7 @@ void kernel_main(u32 kernel_end, unsigned long magic, unsigned long addr, klog(LOG_SUCCESS, "Syscalls Initalized"); pit_install(); - set_pit_count(1); + set_pit_count(2); klog(LOG_SUCCESS, "PIT driver installed"); ata_init(); diff --git a/kernel/network/ethernet.c b/kernel/network/ethernet.c index 1bda07f..a4f2f85 100644 --- a/kernel/network/ethernet.c +++ b/kernel/network/ethernet.c @@ -1,12 +1,13 @@ #include <assert.h> #include <drivers/rtl8139.h> +#include <interrupts.h> #include <kmalloc.h> -#include <string.h> #include <network/arp.h> #include <network/bytes.h> #include <network/ethernet.h> #include <network/ipv4.h> #include <stdio.h> +#include <string.h> struct ETHERNET_HEADER { u8 mac_dst[6]; @@ -69,7 +70,6 @@ void handle_ethernet(const u8 *packet, u64 packet_length) { void send_ethernet_packet(u8 mac_dst[6], u16 type, u8 *payload, u64 payload_length) { - assert(payload_length <= 1500); // FIXME: Janky allocation, do this better u64 buffer_size = sizeof(struct ETHERNET_HEADER) + payload_length + sizeof(u32); diff --git a/kernel/network/tcp.c b/kernel/network/tcp.c index d171722..2dc7180 100644 --- a/kernel/network/tcp.c +++ b/kernel/network/tcp.c @@ -6,23 +6,12 @@ #include <network/arp.h> #include <network/bytes.h> #include <network/ipv4.h> +#include <network/tcp.h> #include <network/udp.h> #include <random.h> -#define CWR (1 << 7) -#define ECE (1 << 6) -#define URG (1 << 5) -#define ACK (1 << 4) -#define PSH (1 << 3) -#define RST (1 << 2) -#define SYN (1 << 1) -#define FIN (1 << 0) - #define MSS 536 -// FIXME: This should be dynamic -#define WINDOW_SIZE 4096 - struct __attribute__((__packed__)) TCP_HEADER { u16 src_port; u16 dst_port; @@ -36,36 +25,9 @@ struct __attribute__((__packed__)) TCP_HEADER { u16 urgent_pointer; }; -struct __attribute__((__packed__)) PSEUDO_TCP_HEADER { - u32 src_addr; - u32 dst_addr; - u8 zero; - u8 protocol; - u16 tcp_length; - u16 src_port; - u16 dst_port; - u32 seq_num; - u32 ack_num; - u8 reserved : 4; - u8 data_offset : 4; - u8 flags; - u16 window_size; - u16 checksum_zero; // ????? - u16 urgent_pointer; -}; - -void tcp_wait_reply(struct TcpConnection *con) { - for (;;) { - if (con->unhandled_packet) { - return; - } - switch_task(); - } -} - -u16 tcp_checksum(u16 *buffer, int size) { - unsigned long cksum = 0; - while (size > 1) { +u16 tcp_checksum(u16 *buffer, u32 size) { + u32 cksum = 0; + for (; size > 1;) { cksum += *buffer++; size -= sizeof(u16); } @@ -90,6 +52,7 @@ u16 tcp_calculate_checksum(ipv4_t src_ip, u32 dst_ip, const u8 *payload, int buffer_length = pseudo + header->data_offset * sizeof(u32) + payload_length; u8 buffer[buffer_length]; + u8 *ptr = buffer; memcpy(ptr, &src_ip.d, sizeof(u32)); ptr += sizeof(u32); @@ -109,70 +72,25 @@ u16 tcp_calculate_checksum(ipv4_t src_ip, u32 dst_ip, const u8 *payload, return tcp_checksum((u16 *)buffer, buffer_length); } -struct TcpPacket { - u32 time; - u32 seq_num; - u16 payload_length; - u8 *buffer; - u16 length; -}; - static void tcp_send(struct TcpConnection *con, u8 *buffer, u16 length, u32 seq_num, u32 payload_length) { - if (payload_length > 0) { - struct TcpPacket *packet = kmalloc(sizeof(struct TcpPacket)); - assert(packet); - packet->time = pit_num_ms(); - packet->seq_num = seq_num; - packet->buffer = buffer; - packet->length = length; - packet->payload_length = payload_length; - - assert(relist_add(&con->inflight, packet, NULL)); - } send_ipv4_packet((ipv4_t){.d = con->outgoing_ip}, 6, buffer, length); } -void tcp_resend_packets(struct TcpConnection *con) { - if (0 == con->inflight.num_entries) { - return; - } - int did_resend = 0; - for (u32 i = 0;; i++) { - struct TcpPacket *packet; - int end; - if (!relist_get(&con->inflight, i, (void *)&packet, &end)) { - if (end) { - break; - } - continue; - } - if (packet->time + 200 > pit_num_ms()) { - continue; - } - // resend the packet - did_resend = 1; - relist_remove(&con->inflight, i); - tcp_send(con, packet->buffer, packet->length, packet->seq_num, - packet->payload_length); - kfree(packet); - } - if (did_resend) { - con->max_inflight = 1; - con->window_size = MSS; - } -} - void tcp_send_empty_payload(struct TcpConnection *con, u8 flags) { struct TCP_HEADER header = {0}; header.src_port = htons(con->incoming_port); header.dst_port = htons(con->outgoing_port); - header.seq_num = htonl(con->seq); - header.ack_num = htonl(con->ack); + header.seq_num = htonl(con->snd_nxt); + if (flags & ACK) { + header.ack_num = htonl(con->sent_ack); + } else { + header.ack_num = 0; + } header.data_offset = 5; header.reserved = 0; header.flags = flags; - header.window_size = htons(WINDOW_SIZE); + header.window_size = htons(con->rcv_wnd); header.urgent_pointer = 0; u8 payload[0]; @@ -185,28 +103,41 @@ void tcp_send_empty_payload(struct TcpConnection *con, u8 flags) { memcpy(send_buffer, &header, sizeof(header)); memcpy(send_buffer + sizeof(header), payload, payload_length); - tcp_send(con, send_buffer, send_len, con->seq, 0); -} - -void tcp_close_connection(struct TcpConnection *con) { - tcp_send_empty_payload(con, FIN | ACK); -} + tcp_send(con, send_buffer, send_len, con->snd_nxt, 0); -void tcp_send_ack(struct TcpConnection *con) { - tcp_send_empty_payload(con, ACK); + con->snd_nxt += (flags & SYN) ? 1 : 0; + con->snd_nxt += (flags & FIN) ? 1 : 0; + con->snd_max = max(con->snd_nxt, con->snd_max); } -void tcp_send_syn(struct TcpConnection *con) { - tcp_send_empty_payload(con, SYN); - con->seq++; +void tcp_close_connection(struct TcpConnection *con) { + if (TCP_STATE_CLOSE_WAIT == con->state) { + tcp_send_empty_payload(con, FIN); + con->state = TCP_STATE_LAST_ACK; + return; + } + if (TCP_STATE_ESTABLISHED == con->state) { + tcp_send_empty_payload(con, FIN); + con->state = TCP_STATE_FIN_WAIT1; + return; + } + if (TCP_STATE_SYN_RECIEVED == con->state) { + tcp_send_empty_payload(con, FIN); + con->state = TCP_STATE_FIN_WAIT1; + return; + } + if (TCP_STATE_SYN_SENT == con->state) { + con->state = TCP_STATE_CLOSED; + // TODO: Cleanup + return; + } } u16 tcp_can_send(struct TcpConnection *con) { - if (con->inflight.num_entries > con->max_inflight) { - tcp_resend_packets(con); + if (TCP_STATE_CLOSED == con->state) { return 0; } - return con->current_window_size; + return con->snd_una + con->snd_wnd - con->snd_max; } int send_tcp_packet(struct TcpConnection *con, const u8 *payload, @@ -215,23 +146,24 @@ int send_tcp_packet(struct TcpConnection *con, const u8 *payload, return 0; } - if (payload_length > MSS) { - if (0 == send_tcp_packet(con, payload, MSS)) { + u16 len = min(1000, payload_length); + if (payload_length > len) { + if (0 == send_tcp_packet(con, payload, len)) { return 0; } - payload_length -= MSS; - payload += MSS; + payload_length -= len; + payload += len; return send_tcp_packet(con, payload, payload_length); } struct TCP_HEADER header = {0}; header.src_port = htons(con->incoming_port); header.dst_port = htons(con->outgoing_port); - header.seq_num = htonl(con->seq); - header.ack_num = htonl(con->ack); + header.seq_num = htonl(con->snd_nxt); + header.ack_num = htonl(con->sent_ack); header.data_offset = 5; header.reserved = 0; header.flags = PSH | ACK; - header.window_size = htons(WINDOW_SIZE); + header.window_size = htons(con->rcv_wnd); header.urgent_pointer = 0; header.checksum = tcp_calculate_checksum( ip_address, con->outgoing_ip, (const u8 *)payload, payload_length, @@ -242,9 +174,10 @@ int send_tcp_packet(struct TcpConnection *con, const u8 *payload, memcpy(send_buffer, &header, sizeof(header)); memcpy(send_buffer + sizeof(header), payload, payload_length); - tcp_send(con, send_buffer, send_len, con->seq, payload_length); + tcp_send(con, send_buffer, send_len, con->snd_nxt, payload_length); - con->seq += payload_length; + con->snd_nxt += payload_length; + con->snd_max = max(con->snd_nxt, con->snd_max); return 1; } @@ -272,97 +205,115 @@ void handle_tcp(ipv4_t src_ip, ipv4_t dst_ip, const u8 *payload, u32 seq_num = htonl(n_seq_num); u32 ack_num = htonl(n_ack_num); u16 window_size = htons(n_window_size); + struct TcpConnection *con = + tcp_find_connection(src_ip, src_port, dst_ip, dst_port); - (void)ack_num; + if (con->state == TCP_STATE_LISTEN || con->state == TCP_STATE_SYN_SENT) { + con->rcv_nxt = seq_num; + } - if (SYN == flags) { - struct TcpConnection *con = - internal_tcp_incoming(src_ip.d, src_port, 0, dst_port); - if (!con) { - return; - } - con->window_size = window_size; - con->current_window_size = MSS; - con->ack = seq_num + 1; - tcp_send_empty_payload(con, SYN | ACK); - con->seq++; + u32 seq_num_end = seq_num + tcp_payload_length - 1; + if (!((con->rcv_nxt <= seq_num) && seq_num < con->rcv_nxt + con->rcv_wnd) && + !((con->rcv_nxt <= seq_num_end) && + seq_num_end < con->rcv_nxt + con->rcv_wnd)) { + kprintf("seq_num: %d\n", seq_num); + kprintf("seq_num_end: %d\n", seq_num_end); + kprintf("con->rcv_nxt: %d\n", con->rcv_nxt); + kprintf("con->rcv_wnd: %d\n", con->rcv_wnd); + // Invalid segment + kprintf("invalid segment\n"); return; } - struct TcpConnection *incoming_connection = - tcp_find_connection(src_ip, src_port, dst_port); - if (!incoming_connection) { - kprintf("unable to find open port for incoming connection\n"); + if (ack_num > con->snd_max) { + // TODO: Odd ACK number, what should be done? + kprintf("odd ACK\n"); return; } - incoming_connection->window_size = window_size; - incoming_connection->unhandled_packet = 1; - if (0 != (flags & RST)) { - klog("Requested port is closed", LOG_NOTE); - incoming_connection->dead = 1; + + if (ack_num < con->snd_una) { + // TODO duplicate ACK + kprintf("duplicate ACK\n"); return; } - if (ACK == flags) { - if (0 == incoming_connection->handshake_state) { - // Then it is probably a response to the SYN|ACK we sent. - incoming_connection->handshake_state = 1; - return; + + con->snd_wnd = window_size; + con->snd_una = ack_num; + + con->sent_ack = max(con->sent_ack, seq_num + tcp_payload_length); + if (FIN & flags) { + con->sent_ack++; + } + + switch (con->state) { + case TCP_STATE_LISTEN: { + if (SYN & flags) { + tcp_send_empty_payload(con, SYN | ACK); + con->state = TCP_STATE_SYN_RECIEVED; + con->rcv_nxt++; + break; } + break; } - if ((SYN | ACK) == flags) { - assert(0 == incoming_connection->handshake_state); - incoming_connection->handshake_state = 1; - incoming_connection->ack = seq_num + 1; - tcp_send_ack(incoming_connection); - return; + case TCP_STATE_SYN_RECIEVED: { + if (ACK & flags) { + con->state = TCP_STATE_ESTABLISHED; + break; + } + break; + } + case TCP_STATE_SYN_SENT: { + if ((ACK & flags) && (SYN & flags)) { + tcp_send_empty_payload(con, ACK); + con->state = TCP_STATE_ESTABLISHED; + con->rcv_nxt++; + break; + } + break; } - if (ACK & flags) { - incoming_connection->seq_ack = ack_num; - if (incoming_connection->inflight.num_entries > 0) { - for (u32 i = 0;; i++) { - struct TcpPacket *packet; - int end; - if (!relist_get(&incoming_connection->inflight, i, (void *)&packet, - &end)) { - if (end) { - break; - } - continue; - } - if (packet->seq_num + packet->payload_length > ack_num) { - continue; - } - relist_remove(&incoming_connection->inflight, i); - kfree(packet->buffer); - kfree(packet); - break; - } + case TCP_STATE_ESTABLISHED: { + if (FIN & flags) { + tcp_send_empty_payload(con, ACK); + con->state = TCP_STATE_CLOSE_WAIT; + break; } - tcp_resend_packets(incoming_connection); - if (0 == incoming_connection->inflight.num_entries) { - incoming_connection->max_inflight++; - u32 rest = incoming_connection->window_size - - incoming_connection->current_window_size; - if (rest > 0) { - incoming_connection->current_window_size += min(rest, MSS); - } + if (tcp_payload_length > 0) { + int rc = ringbuffer_write(&con->incoming_buffer, tcp_payload, + tcp_payload_length); + con->rcv_nxt += rc; + con->rcv_wnd = ringbuffer_unused(&con->incoming_buffer); + tcp_send_empty_payload(con, ACK); } + break; } - if (tcp_payload_length > 0) { - u32 len = ringbuffer_write(&incoming_connection->incoming_buffer, - tcp_payload, tcp_payload_length); - assert(len == tcp_payload_length); - incoming_connection->ack += len; - tcp_send_ack(incoming_connection); + case TCP_STATE_FIN_WAIT1: { + if ((ACK & flags) && (FIN & flags)) { + tcp_send_empty_payload(con, ACK); + con->state = TCP_STATE_TIME_WAIT; + break; + } + if (ACK & flags) { + con->state = TCP_STATE_FIN_WAIT2; + break; + } + if (FIN & flags) { + tcp_send_empty_payload(con, ACK); + con->state = TCP_STATE_CLOSING; + break; + } + break; } - if (0 != (flags & FIN)) { - incoming_connection->ack++; - - tcp_send_empty_payload(incoming_connection, FIN | ACK); - incoming_connection->seq++; - - incoming_connection->dead = 1; // FIXME: It should wait for a ACK - // of the FIN before the connection - // is closed. + case TCP_STATE_LAST_ACK: { + if (ACK & flags) { + // TODO: cleanup + con->state = TCP_STATE_CLOSED; + break; + } + break; + } + default: { + klog(LOG_WARN, "TCP state not handled %d", con->state); + break; } + }; } diff --git a/kernel/network/tcp.h b/kernel/network/tcp.h index ec253bd..90975e4 100644 --- a/kernel/network/tcp.h +++ b/kernel/network/tcp.h @@ -1,9 +1,31 @@ #include <socket.h> #include <typedefs.h> -void tcp_send_syn(struct TcpConnection *con); -void tcp_wait_reply(struct TcpConnection *con); -void handle_tcp(ipv4_t src_ip, ipv4_t dst_ip, const u8 *payload, u32 payload_length); + +#define CWR (1 << 7) +#define ECE (1 << 6) +#define URG (1 << 5) +#define ACK (1 << 4) +#define PSH (1 << 3) +#define RST (1 << 2) +#define SYN (1 << 1) +#define FIN (1 << 0) + +#define TCP_STATE_CLOSED 0 +#define TCP_STATE_LISTEN 1 +#define TCP_STATE_SYN_SENT 2 +#define TCP_STATE_SYN_RECIEVED 3 +#define TCP_STATE_ESTABLISHED 4 +#define TCP_STATE_CLOSE_WAIT 5 +#define TCP_STATE_FIN_WAIT1 6 +#define TCP_STATE_CLOSING 7 +#define TCP_STATE_LAST_ACK 8 +#define TCP_STATE_FIN_WAIT2 9 +#define TCP_STATE_TIME_WAIT 10 + +void handle_tcp(ipv4_t src_ip, ipv4_t dst_ip, const u8 *payload, + u32 payload_length); int send_tcp_packet(struct TcpConnection *con, const u8 *payload, u16 payload_length); void tcp_close_connection(struct TcpConnection *con); u16 tcp_can_send(struct TcpConnection *con); +void tcp_send_empty_payload(struct TcpConnection *con, u8 flags); diff --git a/kernel/network/udp.c b/kernel/network/udp.c index 0c8d6e9..c0a5237 100644 --- a/kernel/network/udp.c +++ b/kernel/network/udp.c @@ -24,7 +24,8 @@ void send_udp_packet(struct sockaddr_in *src, const struct sockaddr_in *dst, kfree(packet); } -void handle_udp(ipv4_t src_ip, ipv4_t dst_ip, const u8 *payload, u32 packet_length) { +void handle_udp(ipv4_t src_ip, ipv4_t dst_ip, const u8 *payload, + u32 packet_length) { (void)dst_ip; if (packet_length < sizeof(u16[4])) { return; diff --git a/kernel/sched/scheduler.c b/kernel/sched/scheduler.c index 31d5257..a2b6091 100644 --- a/kernel/sched/scheduler.c +++ b/kernel/sched/scheduler.c @@ -134,6 +134,7 @@ process_t *create_process(process_t *p, u32 esp, u32 eip) { continue; } if (out) { + out->inode->ref++; out->reference_count++; } } @@ -185,6 +186,7 @@ void tasking_init(void) { int i = 0; void free_process(process_t *p) { + disable_interrupts(); // free_process() will purge all contents such as allocated frames // out of the current process. This will be called by exit() and // exec*(). @@ -210,8 +212,9 @@ void free_process(process_t *p) { } void exit_process(process_t *p, int status) { - disable_interrupts(); assert(p->pid != 1); + disable_interrupts(); + p->dead = 1; if (p->parent) { p->parent->halts[WAIT_CHILD_HALT] = 0; p->parent->child_rc = status; @@ -240,7 +243,6 @@ void exit_process(process_t *p, int status) { tmp = tmp->next; } free_process(p); - p->dead = 1; if (current_task == p) { switch_task(); } @@ -248,7 +250,7 @@ void exit_process(process_t *p, int status) { void exit(int status) { exit_process(current_task, status); - switch_task(); + assert(0); } u32 setup_stack(u32 stack_pointer, int argc, char **argv, int *err) { @@ -365,6 +367,11 @@ int isset_fdhalt(process_t *p, int *empty) { if (NULL == p) { p = current_task; } + disable_interrupts(); + if (p->dead) { + enable_interrupts(); + return 1; + } int blocked = 0; struct list *read_list = &p->read_list; struct list *write_list = &p->write_list; @@ -378,6 +385,7 @@ int isset_fdhalt(process_t *p, int *empty) { *empty = 0; if (inode->_has_data) { if (inode->_has_data(inode)) { + enable_interrupts(); return 0; } } @@ -391,6 +399,7 @@ int isset_fdhalt(process_t *p, int *empty) { *empty = 0; if (inode->_can_write) { if (inode->_can_write(inode)) { + enable_interrupts(); return 0; } } @@ -403,11 +412,12 @@ int isset_fdhalt(process_t *p, int *empty) { } *empty = 0; if (!inode->is_open) { - kprintf("is_open\n"); + enable_interrupts(); return 0; } blocked = 1; } + enable_interrupts(); return blocked; } @@ -512,7 +522,7 @@ void switch_task() { if (current_task->dead) { current_task = current_task->next; - if(!current_task) { + if (!current_task) { current_task = ready_queue; } } else { diff --git a/kernel/sched/scheduler.h b/kernel/sched/scheduler.h index 7a8bf0c..85c2a4c 100644 --- a/kernel/sched/scheduler.h +++ b/kernel/sched/scheduler.h @@ -4,8 +4,8 @@ typedef struct Process process_t; #include <fs/ext2.h> #include <fs/vfs.h> #include <lib/list.h> -#include <lib/stack.h> #include <lib/relist.h> +#include <lib/stack.h> #include <mmu.h> #include <signal.h> #include <stdbool.h> diff --git a/kernel/socket.c b/kernel/socket.c index 79121e7..5aeeb93 100644 --- a/kernel/socket.c +++ b/kernel/socket.c @@ -3,6 +3,7 @@ #include <fs/devfs.h> #include <fs/tmpfs.h> #include <interrupts.h> +#include <lib/ringbuffer.h> #include <math.h> #include <network/bytes.h> #include <network/tcp.h> @@ -10,16 +11,15 @@ #include <poll.h> #include <sched/scheduler.h> #include <socket.h> +#include <stdatomic.h> #include <sys/socket.h> struct list open_udp_connections; struct list open_tcp_connections; -struct list open_tcp_listen; void global_socket_init(void) { list_init(&open_udp_connections); list_init(&open_tcp_connections); - list_init(&open_tcp_listen); } OPEN_UNIX_SOCKET *un_sockets[100] = {0}; @@ -32,13 +32,15 @@ void gen_ipv4(ipv4_t *ip, u8 i1, u8 i2, u8 i3, u8 i4) { } struct TcpConnection *tcp_find_connection(ipv4_t src_ip, u16 src_port, - u16 dst_port) { - (void)src_ip; + ipv4_t dst_ip, u16 dst_port) { for (int i = 0;; i++) { struct TcpConnection *c; if (!list_get(&open_tcp_connections, i, (void **)&c)) { break; } + if (TCP_STATE_CLOSED == c->state) { + continue; + } if (c->incoming_port == dst_port && c->outgoing_port == src_port) { return c; } @@ -64,50 +66,10 @@ struct UdpConnection *udp_find_connection(ipv4_t src_ip, u16 src_port, return NULL; } -struct TcpListen *tcp_find_listen(u16 port) { - for (int i = 0;; i++) { - struct TcpListen *c; - if (!list_get(&open_tcp_listen, i, (void **)&c)) { - break; - } - if (c->port == port) { - return c; - } - } - return NULL; -} - -struct TcpConnection *internal_tcp_incoming(u32 src_ip, u16 src_port, - u32 dst_ip, u16 dst_port) { - struct TcpListen *listen = tcp_find_listen(dst_port); - if (!listen) { - return NULL; - } - - struct TcpConnection *con = kcalloc(1, sizeof(struct TcpConnection)); - - int connection_id; - list_add(&open_tcp_connections, con, &connection_id); - - con->current_window_size = 536; - con->outgoing_ip = src_ip; - con->outgoing_port = src_port; - con->incoming_ip = dst_ip; - con->incoming_port = dst_port; - con->no_delay = 0; - - ringbuffer_init(&con->incoming_buffer, 8192); - ringbuffer_init(&con->outgoing_buffer, 8192); - relist_init(&con->inflight); - con->max_inflight = 1; - stack_push(&listen->incoming_connections, con); - return con; -} - int tcp_sync_buffer(vfs_fd_t *fd) { struct TcpConnection *con = fd->inode->internal_object; assert(con); - if (con->dead) { + if (TCP_STATE_CLOSED == con->state) { return 0; } @@ -117,21 +79,22 @@ int tcp_sync_buffer(vfs_fd_t *fd) { return 0; } - send_buffer_len = min(tcp_can_send(con), send_buffer_len); - if(0 == send_buffer_len) { - return 0; - } + u32 len = min(tcp_can_send(con), send_buffer_len); - char *send_buffer = kmalloc(send_buffer_len); - assert(ringbuffer_read(rb, send_buffer, send_buffer_len) == send_buffer_len); - send_tcp_packet(con, send_buffer, send_buffer_len); + char *send_buffer = kmalloc(len); + assert(ringbuffer_read(rb, send_buffer, len) == len); + send_tcp_packet(con, send_buffer, len); kfree(send_buffer); - return 1; + if (len < send_buffer_len) { + return 0; + } else { + return 1; + } } void tcp_close(vfs_fd_t *fd) { struct TcpConnection *con = fd->inode->internal_object; - + assert(con); tcp_sync_buffer(fd); tcp_close_connection(con); @@ -140,23 +103,40 @@ void tcp_close(vfs_fd_t *fd) { int tcp_read(u8 *buffer, u64 offset, u64 len, vfs_fd_t *fd) { struct TcpConnection *con = fd->inode->internal_object; assert(con); - if (con->dead) { - return -EBADF; // TODO: Check if this is correct. - } - u32 rc = ringbuffer_read(&con->incoming_buffer, buffer, len); if (0 == rc && len > 0) { + if (TCP_STATE_ESTABLISHED != con->state) { + return 0; + } return -EWOULDBLOCK; } return rc; } +int tcp_has_data(vfs_inode_t *inode) { + struct TcpConnection *con = inode->internal_object; + return !(ringbuffer_isempty(&con->incoming_buffer)); +} + +int tcp_can_write(vfs_inode_t *inode) { + struct TcpConnection *con = inode->internal_object; + if (con->no_delay) { + return (0 != tcp_can_send(con)); + } + return (ringbuffer_unused(&con->outgoing_buffer) > 0) || + (0 != tcp_can_send(con)); +} + int tcp_write(u8 *buffer, u64 offset, u64 len, vfs_fd_t *fd) { (void)offset; struct TcpConnection *con = fd->inode->internal_object; assert(con); - if (con->dead) { - return -EBADF; // TODO: Check if this is correct. + if (TCP_STATE_ESTABLISHED != con->state) { + return -ENOTCONN; + } + + if (!tcp_can_write(fd->inode)) { + return -EWOULDBLOCK; } len = min(len, tcp_can_send(con)); @@ -174,32 +154,17 @@ int tcp_write(u8 *buffer, u64 offset, u64 len, vfs_fd_t *fd) { struct ringbuffer *rb = &con->outgoing_buffer; if (ringbuffer_unused(rb) < len) { if (!tcp_sync_buffer(fd)) { - return -EWOULDBLOCK; + return 0; } if (!send_tcp_packet(con, buffer, len)) { return -EWOULDBLOCK; } - len = 0; } else { assert(ringbuffer_write(rb, buffer, len) == len); } return len; } -int tcp_has_data(vfs_inode_t *inode) { - struct TcpConnection *con = inode->internal_object; - return !(ringbuffer_isempty(&con->incoming_buffer)); -} - -int tcp_can_write(vfs_inode_t *inode) { - struct TcpConnection *con = inode->internal_object; - if (con->no_delay) { - return (0 != tcp_can_send(con)); - } - return (ringbuffer_unused(&con->outgoing_buffer) > 0) || - (0 != tcp_can_send(con)); -} - int udp_recvfrom(vfs_fd_t *fd, void *buffer, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { struct UdpConnection *con = fd->inode->internal_object; @@ -270,7 +235,6 @@ int udp_has_data(vfs_inode_t *inode) { void udp_close(vfs_fd_t *fd) { struct UdpConnection *con = fd->inode->internal_object; con->dead = 1; - ringbuffer_free(&con->incoming_buffer); return; } @@ -308,34 +272,46 @@ int udp_connect(vfs_fd_t *fd, const struct sockaddr *addr, socklen_t addrlen) { } int tcp_connect(vfs_fd_t *fd, const struct sockaddr *addr, socklen_t addrlen) { + struct TcpConnection *con = fd->inode->internal_object; + assert(AF_INET == addr->sa_family); const struct sockaddr_in *in_addr = (const struct sockaddr_in *)addr; - struct TcpConnection *con = kcalloc(1, sizeof(struct TcpConnection)); - if (!con) { - return -ENOMEM; - } + con->state = TCP_STATE_LISTEN; con->incoming_port = 1337; // TODO con->outgoing_ip = in_addr->sin_addr.s_addr; con->outgoing_port = ntohs(in_addr->sin_port); - con->current_window_size = 536; + + con->max_seg = 1; + + con->rcv_wnd = 4096; + con->rcv_nxt = 0; + con->rcv_adv = 0; + + con->snd_una = 0; + con->snd_nxt = 0; + con->snd_max = 0; + con->snd_wnd = 0; + con->sent_ack = 0; ringbuffer_init(&con->incoming_buffer, 8192); ringbuffer_init(&con->outgoing_buffer, 8192); + con->snd_wnd = ringbuffer_unused(&con->incoming_buffer); list_add(&open_tcp_connections, con, NULL); - relist_init(&con->inflight); - con->max_inflight = 1; - tcp_send_syn(con); + con->state = TCP_STATE_SYN_SENT; + tcp_send_empty_payload(con, SYN); for (;;) { - tcp_wait_reply(con); - if (con->dead) { // Port is probably closed + switch_task(); + if (TCP_STATE_CLOSED == con->state) { return -ECONNREFUSED; } - if (0 != con->handshake_state) { + if (TCP_STATE_ESTABLISHED == con->state) { break; } + assert(TCP_STATE_SYN_SENT == con->state || + TCP_STATE_ESTABLISHED == con->state); } fd->inode->_has_data = tcp_has_data; @@ -519,21 +495,7 @@ int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { FS_TYPE_UNIX_SOCKET); return 0; } else if (AF_INET == s->domain) { - struct sockaddr_in *in = (struct sockaddr_in *)addr; - - struct TcpListen *tcp_listen = kmalloc(sizeof(struct TcpListen)); - if (!tcp_listen) { - return -ENOMEM; - } - tcp_listen->ip = in->sin_addr.s_addr; - tcp_listen->port = ntohs(in->sin_port); - stack_init(&tcp_listen->incoming_connections); - - s->object = tcp_listen; - - inode->_has_data = tcp_listen_has_data; - - list_add(&open_tcp_listen, tcp_listen, NULL); + assert(0); return 0; } ASSERT_NOT_REACHED; @@ -566,6 +528,31 @@ void socket_close(vfs_fd_t *fd) { fd->inode->is_open = 0; } +int tcp_create_fd() { + struct TcpConnection *con = kmalloc(sizeof(struct TcpConnection)); + if (!con) { + return -ENOMEM; + } + con->state = TCP_STATE_CLOSED; + + vfs_inode_t *inode = vfs_create_inode( + 0 /*inode_num*/, FS_TYPE_UNIX_SOCKET, NULL, always_can_write, 1, con, + 0 /*file_size*/, NULL /*open*/, NULL /*create_file*/, tcp_read, tcp_write, + NULL /*close*/, NULL /*create_directory*/, NULL /*get_vm_object*/, + NULL /*truncate*/, NULL /*stat*/, NULL /*send_signal*/, tcp_connect); + if (!inode) { + kfree(con); + return -ENOMEM; + } + int fd = vfs_create_fd(O_RDWR, 0, 0 /*is_tty*/, inode, NULL); + if (fd < 0) { + kfree(con); + kfree(inode); + return fd; + } + return fd; +} + int socket(int domain, int type, int protocol) { int rc = 0; vfs_inode_t *inode = NULL; @@ -612,20 +599,15 @@ int socket(int domain, int type, int protocol) { } if (AF_INET == domain) { int is_udp = (SOCK_DGRAM == type); - - void *connect_handler = NULL; - if (is_udp) { - connect_handler = udp_connect; - } else { - connect_handler = tcp_connect; + if (!is_udp) { + return tcp_create_fd(); } vfs_inode_t *inode = vfs_create_inode( 0 /*inode_num*/, FS_TYPE_UNIX_SOCKET, NULL, always_can_write, 1, new_socket, 0 /*file_size*/, NULL /*open*/, NULL /*create_file*/, NULL, NULL, NULL /*close*/, NULL /*create_directory*/, NULL /*get_vm_object*/, - NULL /*truncate*/, NULL /*stat*/, NULL /*send_signal*/, - connect_handler); + NULL /*truncate*/, NULL /*stat*/, NULL /*send_signal*/, udp_connect); if (!inode) { rc = -ENOMEM; goto socket_error; diff --git a/kernel/socket.h b/kernel/socket.h index 0cb6865..0c419fe 100644 --- a/kernel/socket.h +++ b/kernel/socket.h @@ -42,7 +42,9 @@ struct UdpConnection { }; struct TcpConnection { - int dead; + + int state; + u16 incoming_port; u32 incoming_ip; u32 outgoing_ip; @@ -52,26 +54,27 @@ struct TcpConnection { struct ringbuffer incoming_buffer; struct ringbuffer outgoing_buffer; - struct relist inflight; - u8 max_inflight; - int no_delay; u32 current_window_size; u32 window_size; - u32 seq; - u32 seq_ack; - u32 ack; + u32 sent_ack; + u32 recieved_ack; - int handshake_state; -}; + u32 max_seg; + + u32 rcv_wnd; + u32 rcv_nxt; + u32 rcv_adv; -struct TcpConnection *tcp_get_connection(u32 socket, process_t *p); -struct TcpConnection *internal_tcp_incoming(u32 src_ip, u16 src_port, - u32 dst_ip, u16 dst_port); + u32 snd_una; + u32 snd_nxt; + u32 snd_max; + u32 snd_wnd; +}; struct TcpConnection *tcp_find_connection(ipv4_t src_ip, u16 src_port, - u16 dst_port); + ipv4_t dst_ip, u16 dst_port); struct UdpConnection *udp_find_connection(ipv4_t src_ip, u16 src_port, u16 dst_port); |