summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kernel/drivers/pit.c2
-rw-r--r--kernel/drivers/rtl8139.c19
-rw-r--r--kernel/fs/vfs.c7
-rw-r--r--kernel/init/kernel.c2
-rw-r--r--kernel/network/ethernet.c4
-rw-r--r--kernel/network/tcp.c337
-rw-r--r--kernel/network/tcp.h28
-rw-r--r--kernel/network/udp.c3
-rw-r--r--kernel/sched/scheduler.c20
-rw-r--r--kernel/sched/scheduler.h2
-rw-r--r--kernel/socket.c204
-rw-r--r--kernel/socket.h29
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);