Skip to content

Commit c408bdb

Browse files
tcp tidyups, crash fixes on ethernet stack init
1 parent c47639f commit c408bdb

File tree

14 files changed

+432
-157
lines changed

14 files changed

+432
-157
lines changed

include/tcp.h

Lines changed: 125 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,18 @@ typedef struct tcp_ordered_list_t {
9999
struct tcp_ordered_list_t* next;
100100
} tcp_ordered_list_t;
101101

102+
typedef struct tcp_conn_t tcp_conn_t;
103+
104+
typedef struct pending_node {
105+
tcp_conn_t *conn;
106+
struct pending_node *next;
107+
} pending_node_t;
108+
109+
typedef struct {
110+
pending_node_t *head;
111+
pending_node_t *tail;
112+
} queue_t;
113+
102114
typedef struct tcp_conn_t
103115
{
104116
tcp_state_t state;
@@ -141,6 +153,10 @@ typedef struct tcp_conn_t
141153
uint32_t msl_time; // Maximum socket lifetime timeout or 0
142154

143155
tcp_ordered_list_t* segment_list;
156+
157+
int backlog;
158+
159+
queue_t* pending;
144160
} tcp_conn_t;
145161

146162
/**
@@ -166,6 +182,8 @@ typedef enum tcp_error_code_t {
166182
TCP_ERROR_INVALID_SOCKET = -9,
167183
TCP_ERROR_CONNECTION_FAILED = -10,
168184
TCP_LAST_ERROR = -11,
185+
TCP_ERROR_NOT_LISTENING = -12,
186+
TCP_ERROR_WOULD_BLOCK = -13,
169187
} tcp_error_code_t;
170188

171189
/**
@@ -246,4 +264,110 @@ const char* socket_error(int error_code);
246264
/**
247265
* @brief Idle loop ran from timer ISR
248266
*/
249-
void tcp_idle();
267+
void tcp_idle();
268+
269+
/**
270+
* @brief Allocate a new empty queue
271+
*
272+
* @return queue_t* newly allocated queue, or NULL on failure
273+
*/
274+
queue_t* queue_new(void);
275+
276+
/**
277+
* @brief Push a tcp_conn_t into the queue
278+
*
279+
* @param q queue
280+
* @param conn TCP connection to enqueue
281+
*/
282+
void queue_push(queue_t *q, tcp_conn_t *conn);
283+
284+
/**
285+
* @brief Pop the oldest tcp_conn_t from the queue
286+
*
287+
* @param q queue
288+
* @return tcp_conn_t* dequeued connection, or NULL if empty
289+
*/
290+
tcp_conn_t* queue_pop(queue_t *q);
291+
292+
/**
293+
* @brief Return true if queue is empty
294+
*
295+
* @param q queue
296+
* @return true if empty, false otherwise
297+
*/
298+
bool queue_empty(queue_t *q);
299+
300+
/**
301+
* @brief Free all nodes in the queue and the queue itself
302+
*
303+
* @param q queue
304+
*/
305+
void queue_free(queue_t *q);
306+
307+
/**
308+
* @brief Allocate a new file descriptor for a TCP connection.
309+
* @note O(n) time
310+
*
311+
* @param conn Pointer to the TCP connection.
312+
* @return File descriptor number on success, or -1 on failure.
313+
*/
314+
int tcp_allocate_fd(tcp_conn_t* conn);
315+
316+
/**
317+
* @brief Free a previously allocated TCP file descriptor.
318+
* @note O(1) time
319+
*
320+
* @param x File descriptor number to free.
321+
*/
322+
void tcp_free_fd(int x);
323+
324+
/**
325+
* @brief Find a TCP connection by its file descriptor.
326+
* @note O(1) time
327+
*
328+
* @param x File descriptor number.
329+
* @return Pointer to the TCP connection if found, or NULL if not found.
330+
*/
331+
tcp_conn_t* tcp_find_by_fd(int x);
332+
333+
/**
334+
* @brief Dump debug info for a TCP segment
335+
*
336+
* @param encap_packet encapsulating IP packet
337+
* @param segment TCP segment
338+
* @param options TCP options
339+
* @param len TCP length
340+
* @param our_checksum calculated checksum
341+
*/
342+
void tcp_dump_segment(bool in, tcp_conn_t* conn, const ip_packet_t* encap_packet, const tcp_segment_t* segment, const tcp_options_t* options, size_t len, uint16_t our_checksum);
343+
344+
/**
345+
* @brief Create a listening TCP socket.
346+
*
347+
* Binds a TCP connection control block (TCB) to the given local address
348+
* and port, and transitions it into the LISTEN state. A pending connection
349+
* queue is created to hold half‑open connections until they are accepted.
350+
*
351+
* @param addr Local IPv4 address to bind to (network byte order).
352+
* @param port Local TCP port to listen on (host byte order).
353+
* @param backlog Maximum number of pending connections that may be queued.
354+
*
355+
* @return File descriptor for the listening socket on success, or a
356+
* negative TCP_ERROR code on failure.
357+
*/
358+
int tcp_listen(uint32_t addr, uint16_t port, int backlog);
359+
360+
/**
361+
* @brief Accept an incoming connection on a listening socket.
362+
*
363+
* Removes one pending connection from the listening socket’s queue and
364+
* allocates a new file descriptor for it. The connection will be in the
365+
* ESTABLISHED state upon return.
366+
*
367+
* @param socket File descriptor of a socket previously placed in the
368+
* LISTEN state using tcp_listen().
369+
*
370+
* @return File descriptor for the accepted connection on success, or a
371+
* negative TCP_ERROR code on failure.
372+
*/
373+
int tcp_accept(int socket);

src/ethernet.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ bool ethernet_register_iee802_number(uint16_t protocol_number, ethernet_protocol
5454
if (!protocol_handlers) {
5555
return false;
5656
}
57+
memset(protocol_handlers, 0, sizeof(void*) * UINT16_MAX);
5758
}
5859
if (protocol_handlers[protocol_number] == NULL) {
5960
protocol_handlers[protocol_number] = handler;

src/iso9660.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ void *iso_get_directory(void *t) {
251251
dprintf("iso_get_directory size: %d %d %d\n", treeitem->size, info->rootextent_len, treeitem->size ? treeitem->size : info->rootextent_len);
252252
return (void *) parse_directory(treeitem, (iso9660 *) treeitem->opaque,
253253
treeitem->lbapos ? treeitem->lbapos : info->rootextent_lba,
254-
treeitem->size ? treeitem->size : info->rootextent_len * 2048);
254+
treeitem->size ? treeitem->size : (info->rootextent_len == 1 ? 2048 : info->rootextent_len));
255255
} else {
256256
kprintf("*** BUG *** iso_get_directory: null fs_tree_t*!\n");
257257
return NULL;
File renamed without changes.

src/net/debug.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#include <kernel.h>
2+
3+
void tcp_dump_segment(bool in, tcp_conn_t* conn, const ip_packet_t* encap_packet, const tcp_segment_t* segment, const tcp_options_t* options, size_t len, uint16_t our_checksum)
4+
{
5+
#if (TCP_TRACE != 1)
6+
return;
7+
#endif
8+
const char *states[] = { "LISTEN","SYN-SENT","SYN-RECEIVED","ESTABLISHED","FIN-WAIT-1","FIN-WAIT-2","CLOSE-WAIT","CLOSING","LAST-ACK","TIME-WAIT" };
9+
char source_ip[15] = { 0 }, dest_ip[15] = { 0 };
10+
get_ip_str(source_ip, encap_packet->src_ip);
11+
get_ip_str(dest_ip, encap_packet->dst_ip);
12+
dprintf(
13+
"TCP %s: %s %s:%d->%s:%d len=%ld seq=%d ack=%d off=%d flags[%c%c%c%c%c%c%c%c] win=%d, sum=%04x/%04x, urg=%d",
14+
in ? "IN" : "OUT",
15+
conn ? states[conn->state] : "CLOSED",
16+
source_ip,
17+
segment->src_port,
18+
dest_ip,
19+
segment->dst_port,
20+
len,
21+
segment->seq,
22+
segment->ack,
23+
segment->flags.off,
24+
segment->flags.fin ? 'F' : '-',
25+
segment->flags.syn ? 'S' : '-',
26+
segment->flags.rst ? 'R' : '-',
27+
segment->flags.psh ? 'P' : '-',
28+
segment->flags.ack ? 'A' : '-',
29+
segment->flags.urg ? 'U' : '-',
30+
segment->flags.ece ? 'E' : '-',
31+
segment->flags.cwr ? 'C' : '-',
32+
segment->window_size,
33+
segment->checksum,
34+
our_checksum,
35+
segment->urgent
36+
);
37+
if (options && options->mss) {
38+
dprintf(" [opt.mss=%d]", options->mss);
39+
}
40+
dprintf("\n");
41+
}

src/net/descriptor.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#include <kernel.h>
2+
3+
static tcp_conn_t* fd[FD_MAX] = { 0 };
4+
5+
int tcp_allocate_fd(tcp_conn_t* conn)
6+
{
7+
for (size_t x = 0; x < FD_MAX; ++x) {
8+
if (fd[x] == NULL) {
9+
fd[x] = conn;
10+
return x;
11+
}
12+
}
13+
return -1;
14+
}
15+
16+
void tcp_free_fd(int x)
17+
{
18+
if (x >= 0 && x < FD_MAX) {
19+
fd[x] = NULL;
20+
}
21+
}
22+
23+
tcp_conn_t* tcp_find_by_fd(int x)
24+
{
25+
if (x >= 0 && x < FD_MAX) {
26+
return fd[x];
27+
}
28+
return NULL;
29+
}
30+
File renamed without changes.
File renamed without changes.
File renamed without changes.

src/ip.c renamed to src/net/ip.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,10 @@ void ip_idle()
116116
time_t current_time = time(NULL);
117117
packet_queue_item_t* cur = packet_queue;
118118
packet_queue_item_t* last = NULL;
119-
for (; cur; cur = cur->next) {
119+
120+
for (; cur; ) {
121+
/* Save next pointer early, because cur may be freed */
122+
packet_queue_item_t* next = cur->next;
120123

121124
/* Here we determine if the packet is destined for the local net or the
122125
* internet at large. The calculation is actually very easy, we just AND
@@ -129,7 +132,7 @@ void ip_idle()
129132
* is the IP address of the target machine otherwise is the IP of the
130133
* router. This is then used in arp_lookup() to decide which mac address
131134
* we send the packet to.
132-
*
135+
*
133136
* Note that if we have no gateway address everything is considered local.
134137
*
135138
* These addresses are all in network byte order - it doesn't matter, so
@@ -148,19 +151,25 @@ void ip_idle()
148151
/* The ARP for this MAC has come back now, we can send the packet! */
149152
ethernet_send_packet(dst_hardware_addr, (uint8_t*)cur->packet, htons(cur->packet->length), ETHERNET_TYPE_IP);
150153
dequeue_packet(cur, last);
154+
/* do not advance last, because cur was freed */
151155
} else if (is_local && cur->arp_tries < 2 && current_time - cur->last_arp > 0) {
152156
/* After one second, ARP didn't come back, try it again up to 3 times */
153157
cur->arp_tries++;
154158
cur->last_arp = current_time;
155159
arp_send_packet(zero_hardware_addr, arp_dest);
160+
last = cur; /* safe to advance last, we kept cur */
156161
} else if (cur->arp_tries == 3 && current_time - cur->last_arp >= 10) {
157162
/* 3 ARPs have been tried over 3 seconds, and then we waited another ten.
158163
* Packet still didn't get an ARP reply. Dequeue it as a lost packet.
159164
*/
160165
dprintf("Failed ARP resolution after 3 tries to %08x at %d\n", arp_dest, current_time);
161166
dequeue_packet(cur, last);
167+
/* again, don't advance last */
168+
} else {
169+
last = cur; /* still alive, advance last */
162170
}
163-
last = cur;
171+
172+
cur = next; /* always advance from saved next pointer */
164173
}
165174
}
166175
}

0 commit comments

Comments
 (0)