From 9201820097ef333e967f72450dc18ea727c30e2e Mon Sep 17 00:00:00 2001
From: dzwdz
Date: Wed, 24 Aug 2022 00:22:48 +0200
Subject: user/netstack: TCP outgoing

I got on IRC!
---
 src/user/app/netstack/fs.c    | 19 +++++++++++++++++++
 src/user/app/netstack/proto.h |  5 +++++
 src/user/app/netstack/tcp.c   | 43 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 67 insertions(+)

(limited to 'src/user/app')

diff --git a/src/user/app/netstack/fs.c b/src/user/app/netstack/fs.c
index b50e778..f4d9625 100644
--- a/src/user/app/netstack/fs.c
+++ b/src/user/app/netstack/fs.c
@@ -185,6 +185,25 @@ static void fs_open(handle_t reqh, char *path) {
 			respond(NULL, -1);
 		proto = strtok_r(NULL, "/", &save);
 		if (!proto) respond(NULL, -1);
+		if (strcmp(proto, "tcp") == 0) {
+			port_s = strtok_r(NULL, "/", &save);
+			if (port_s) {
+				uint16_t port = strtol(port_s, NULL, 0);
+				h = malloc(sizeof *h);
+				memset(h, 0, sizeof *h);
+				h->type = H_TCP;
+				h->tcp.c = tcpc_new((struct tcp){
+					.dst = port,
+					.ip.dst = dstip,
+				}, tcp_recv_callback, tcp_close_callback, h);
+				if (h->tcp.c) {
+					respond(h, 0);
+				} else {
+					free(h);
+					respond(NULL, -1);
+				}
+			}
+		}
 		if (strcmp(proto, "udp") == 0) {
 			port_s = strtok_r(NULL, "/", &save);
 			if (port_s) {
diff --git a/src/user/app/netstack/proto.h b/src/user/app/netstack/proto.h
index 738f09e..30ff864 100644
--- a/src/user/app/netstack/proto.h
+++ b/src/user/app/netstack/proto.h
@@ -95,6 +95,11 @@ void tcp_listen(
 	void (*on_recv)(void *carg),
 	void (*on_close)(void *carg),
 	void *carg);
+struct tcp_conn *tcpc_new(
+	struct tcp t,
+	void (*on_recv)(void *carg),
+	void (*on_close)(void *carg),
+	void *carg);
 size_t tcpc_tryread(struct tcp_conn *, void *buf, size_t len);
 void tcpc_send(struct tcp_conn *, const void *buf, size_t len);
 void tcpc_close(struct tcp_conn *);
diff --git a/src/user/app/netstack/tcp.c b/src/user/app/netstack/tcp.c
index a1b0759..9e6e3bb 100644
--- a/src/user/app/netstack/tcp.c
+++ b/src/user/app/netstack/tcp.c
@@ -31,7 +31,9 @@ enum {
 
 enum tcp_state {
 	LISTEN,
+	SYN_SENT,
 	SYN_RCVD,
+	ESTABILISHED,
 	LAST_ACK,
 	CLOSED,
 };
@@ -93,6 +95,7 @@ void tcp_listen(
 	void *carg)
 {
 	struct tcp_conn *c = malloc(sizeof *c);
+	memset(c, 0, sizeof *c);
 	c->lport = port;
 	c->lip = state.ip;
 	c->state = LISTEN;
@@ -104,6 +107,35 @@ void tcp_listen(
 	c->rx = (ring_t){malloc(4096), 4096, 0, 0};
 	conns_append(c);
 }
+struct tcp_conn *tcpc_new(
+	struct tcp t,
+	void (*on_recv)(void *carg),
+	void (*on_close)(void *carg),
+	void *carg)
+{
+	struct tcp_conn *c = malloc(sizeof *c);
+	memset(c, 0, sizeof *c);
+	c->lip = t.ip.src ? t.ip.src : state.ip;
+	c->rip = t.ip.dst;
+	c->lport = t.src ? t.src : 50002; // TODO randomize source ports
+	c->rport = t.dst;
+	if (arpcache_get(c->rip, &c->rmac) < 0) {
+		// TODO make arp request, wait for reply
+		eprintf("not in ARP cache, unimplemented");
+		free(c);
+		return NULL;
+	}
+
+	c->state = SYN_SENT;
+	c->on_recv = on_recv;
+	c->on_close = on_close;
+	c->carg = carg;
+	c->rx = (ring_t){malloc(4096), 4096, 0, 0};
+	conns_append(c);
+
+	tcpc_sendraw(c, FlagSYN, NULL, 0);
+	return c;
+}
 size_t tcpc_tryread(struct tcp_conn *c, void *buf, size_t len) {
 	if (!buf) return ring_used(&c->rx);
 	return ring_get(&c->rx, buf, len);
@@ -163,6 +195,17 @@ void tcp_parse(const uint8_t *buf, size_t len, struct ipv4 ip) {
 
 		if (iter->rip == ip.src && iter->rport == srcport) {
 			// TODO doesn't handle seq/ack overflows
+			if (iter->state == SYN_SENT) {
+				if (flags & FlagSYN) {
+					iter->state = ESTABILISHED;
+					iter->lack = seq + 1;
+					tcpc_sendraw(iter, FlagACK, NULL, 0);
+					return;
+				} else {
+					// TODO resend syn?
+					return;
+				}
+			}
 			if (flags & FlagACK) {
 				if (iter->rack < acknum)
 					iter->rack = acknum;
-- 
cgit v1.2.3