From 642b5fb0007b64c77d186fcb018d571152ee1d47 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Mon, 14 Aug 2023 18:51:07 +0200 Subject: reorganization: first steps --- src/user/app/netstack/arp.c | 151 ------------------ src/user/app/netstack/ether.c | 59 -------- src/user/app/netstack/fs.c | 320 --------------------------------------- src/user/app/netstack/icmp.c | 34 ----- src/user/app/netstack/ipv4.c | 216 -------------------------- src/user/app/netstack/netstack.c | 53 ------- src/user/app/netstack/proto.h | 107 ------------- src/user/app/netstack/tcp.c | 268 -------------------------------- src/user/app/netstack/udp.c | 124 --------------- src/user/app/netstack/util.c | 60 -------- src/user/app/netstack/util.h | 44 ------ 11 files changed, 1436 deletions(-) delete mode 100644 src/user/app/netstack/arp.c delete mode 100644 src/user/app/netstack/ether.c delete mode 100644 src/user/app/netstack/fs.c delete mode 100644 src/user/app/netstack/icmp.c delete mode 100644 src/user/app/netstack/ipv4.c delete mode 100644 src/user/app/netstack/netstack.c delete mode 100644 src/user/app/netstack/proto.h delete mode 100644 src/user/app/netstack/tcp.c delete mode 100644 src/user/app/netstack/udp.c delete mode 100644 src/user/app/netstack/util.c delete mode 100644 src/user/app/netstack/util.h (limited to 'src/user/app/netstack') diff --git a/src/user/app/netstack/arp.c b/src/user/app/netstack/arp.c deleted file mode 100644 index 3a1c8da..0000000 --- a/src/user/app/netstack/arp.c +++ /dev/null @@ -1,151 +0,0 @@ -#include "proto.h" -#include "util.h" -#include -#include -#include - -enum { - HdrType = 0, - HdrTypeEther = 1, - ProtoType = 2, - HdrALen = 4, - ProtoALen = 5, - Operation = 6, - OpReq = 1, - OpReply = 2, -}; - -struct arpc { - struct arpc *next; - uint32_t ip; - mac_t mac; -}; -static struct arpc *arpcache; -static void arpcache_put(uint32_t ip, mac_t mac); - -void arp_parse(const uint8_t *buf, size_t len) { - if (len < Operation + 2) return; - uint16_t htype = nget16(buf + HdrType); - uint16_t ptype = nget16(buf + ProtoType); - uint16_t op = nget16(buf + Operation); - - if (!(htype == HdrTypeEther && ptype == ET_IPv4)) return; - enum { /* only valid for this combination of header + proto */ - SrcMAC = 8, - SrcIP = 14, - DstMAC = 18, - DstIP = 24, - }; - if (len < DstIP + 4) return; - arpcache_put(nget32(buf + SrcIP), *(mac_t*)buf + SrcMAC); - - if (op == OpReq) { - uint32_t daddr = nget32(buf + DstIP); - if (daddr == state.ip) { - uint8_t *pkt = ether_start(30, (struct ethernet){ - .dst = (void*)(buf + SrcMAC), - .type = ET_ARP, - }); - nput16(pkt + HdrType, HdrTypeEther); - nput16(pkt + ProtoType, ET_IPv4); - pkt[HdrALen] = 6; - pkt[ProtoALen] = 4; - nput16(pkt + Operation, OpReply); - memcpy(pkt + SrcMAC, state.mac, 6); - nput32(pkt + SrcIP, state.ip); - memcpy(pkt + DstMAC, buf + SrcMAC, 10); /* sender's MAC and IP */ - ether_finish(pkt); - } - } -} - -void arp_request(uint32_t ip) { - enum { - SrcMAC = 8, - SrcIP = 14, - DstMAC = 18, - DstIP = 24, - }; - uint8_t *pkt = ether_start(28, (struct ethernet){ - .src = &state.mac, - .dst = &MAC_BROADCAST, - .type = ET_ARP, - }); - nput16(pkt + HdrType, HdrTypeEther); - nput16(pkt + ProtoType, ET_IPv4); - pkt[HdrALen] = 6; - pkt[ProtoALen] = 4; - nput16(pkt + Operation, OpReq); - memcpy(pkt + SrcMAC, state.mac, 6); - nput32(pkt + SrcIP, state.ip); - memcpy(pkt + DstMAC, &MAC_BROADCAST, 6); - nput32(pkt + DstIP, ip); - ether_finish(pkt); -} - -static void arpcache_put(uint32_t ip, mac_t mac) { - for (struct arpc *iter = arpcache; iter; iter = iter->next) { - if (memcmp(iter->mac, mac, 6) == 0) { - if (iter->ip == ip) return; /* cache entry correct */ - else break; /* cache entry needs updating */ - } - } - struct arpc *e = malloc(sizeof *e); - e->next = arpcache; - e->ip = ip; - memcpy(e->mac, mac, 6); - arpcache = e; -} - -int arpcache_get(uint32_t ip, mac_t *mac) { - for (struct arpc *iter = arpcache; iter; iter = iter->next) { - if (iter->ip == ip) { - if (mac) memcpy(mac, iter->mac, 6); - return 0; - } - } - return -1; -} - -void arp_fsread(hid_t h, long offset) { - const char *fmt = "%08x\t%02x:%02x:%02x:%02x:%02x:%02x\n"; - long linelen = snprintf(NULL, 0, fmt, 0, 1, 2, 3, 4, 5, 6) + 1; - char buf[28]; - assert(linelen <= (long)sizeof(buf)); - if (offset < 0) goto err; - - struct arpc *cur = arpcache; - if (!cur) goto err; - for (; linelen <= offset; offset -= linelen) { - cur = cur->next; - if (!cur) goto err; - } - assert(0 <= offset && offset < linelen); - - snprintf(buf, sizeof buf, fmt, cur->ip, - cur->mac[0], - cur->mac[1], - cur->mac[2], - cur->mac[3], - cur->mac[4], - cur->mac[5]); - _sys_fs_respond(h, buf + offset, linelen - offset, 0); - return; -err: - _sys_fs_respond(h, NULL, -1, 0); -} - -long arp_fswrite(const char *buf, long len, long offset) { - if (offset != -1) return -1; - uint32_t ip; - char tmp[16]; - size_t iplen = len < 15 ? len : 15; - memcpy(tmp, buf, iplen); - tmp[iplen] = '\0'; - if (ip_parse(tmp, &ip) < 0) { - return -1; - } else { - arp_request(ip); - return len; - } -} diff --git a/src/user/app/netstack/ether.c b/src/user/app/netstack/ether.c deleted file mode 100644 index 52abac2..0000000 --- a/src/user/app/netstack/ether.c +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include "proto.h" -#include "util.h" - -enum { - DstMAC = 0, - SrcMAC = 6, - EtherType = 12, - Payload = 14, -}; -struct ethq *ether_queue; - -void ether_parse(const uint8_t *buf, size_t len) { - struct ethernet ether = (struct ethernet){ - .src = (void*)(buf + SrcMAC), - .dst = (void*)(buf + DstMAC), - .type = nget16(buf + EtherType), - }; - - for (struct ethq **iter = ðer_queue; iter && *iter; ) { - struct ethq *qe = *iter; - _sys_fs_respond(qe->h, buf, len, 0); - /* remove entry */ - /* yes, doing it this way here doesn't make sense. i'm preparing for filtering */ - *iter = qe->next; - free(qe); - } - - switch (ether.type) { - case ET_IPv4: - ipv4_parse(buf + Payload, len - Payload, ether); - break; - case ET_ARP: - arp_parse(buf + Payload, len - Payload); - break; - } -} - -static const size_t fhoff = sizeof(size_t); -uint8_t *ether_start(size_t len, struct ethernet ether) { - if (len < 60 - Payload) len = 60 - Payload; - - if (!ether.dst) eprintf("NULL ether.dst!"); // TODO arp? i guess? - if (!ether.src) ether.src = &state.mac; - - uint8_t *buf = malloc(fhoff + Payload + len); - memset(buf, 0, fhoff + Payload + len); - *(size_t*)buf = len + Payload; - memcpy(buf + fhoff + DstMAC, ether.dst, 6); - memcpy(buf + fhoff + SrcMAC, ether.src, 6); - nput16(buf + fhoff + EtherType, ether.type); - return buf + fhoff + Payload; -} -void ether_finish(uint8_t *pkt) { - uint8_t *buf = pkt - Payload - fhoff; - size_t len = *(size_t*)buf; - _sys_write(state.raw_h, buf + fhoff, len, 0, 0); - free(buf); -} diff --git a/src/user/app/netstack/fs.c b/src/user/app/netstack/fs.c deleted file mode 100644 index 6d51c35..0000000 --- a/src/user/app/netstack/fs.c +++ /dev/null @@ -1,320 +0,0 @@ -/* - * path format: - * /net/raw - * raw ethernet frames (read-write) - * /net/arp - * ARP cache (currently read-only) - * /net/connect/0.0.0.0/1.2.3.4/udp/53 - * connect from 0.0.0.0 (any ip) to 1.2.3.4 on udp port 53 - * /net/listen/0.0.0.0/{tcp,udp}/53 - * waits for a connection to any ip on udp port 53 - * open() returns once a connection to ip 0.0.0.0 on udp port 53 is received - */ -#include "proto.h" -#include "util.h" -#include -#include -#include -#include -#include -#include - -enum handle_type { - H_ETHER, - H_TCP, - H_UDP, - H_ARP, -}; - -struct strqueue { - struct strqueue *next; - size_t len; - char buf[]; -}; - -struct handle { - enum handle_type type; - struct { - struct udp_conn *c; - struct strqueue *rx, *rxlast; - } udp; - struct { - struct tcp_conn *c; - size_t readcap; - } tcp; - bool dead; - hid_t reqh; -}; - - -static void tcp_listen_callback(struct tcp_conn *c, void *arg) { - struct handle *h = arg; - h->tcp.c = c; - _sys_fs_respond(h->reqh, h, 0, 0); - h->reqh = -1; -} - -/* also called from recv_enqueue. yes, it's a mess */ -static void tcp_recv_callback(void *arg) { - struct handle *h = arg; - char buf[1024]; - if (h->reqh >= 0) { - if (h->tcp.readcap > sizeof buf) - h->tcp.readcap = sizeof buf; - size_t len = tcpc_tryread(h->tcp.c, buf, h->tcp.readcap); - if (len > 0) { - _sys_fs_respond(h->reqh, buf, len, 0); - h->reqh = -1; - } - } -} - -static void tcp_close_callback(void *arg) { - struct handle *h = arg; - h->dead = true; - if (h->reqh >= 0) { - _sys_fs_respond(h->reqh, NULL, -ECONNRESET, 0); - h->reqh = -1; - return; - } -} - -static void udp_listen_callback(struct udp_conn *c, void *arg) { - struct handle *h = arg; - h->udp.c = c; - _sys_fs_respond(h->reqh, h, 0, 0); - h->reqh = -1; -} - -static void udp_recv_callback(const void *buf, size_t len, void *arg) { - struct handle *h = arg; - if (h->reqh >= 0) { - _sys_fs_respond(h->reqh, buf, len, 0); - h->reqh = -1; - return; - } - struct strqueue *sq = malloc(sizeof(*sq) + len); - sq->next = NULL; - sq->len = len; - memcpy(sq->buf, buf, len); - if (h->udp.rx) { - h->udp.rxlast->next = sq; - h->udp.rxlast = sq; - } else { - h->udp.rx = sq; - h->udp.rxlast = sq; - } -} - -static void recv_enqueue(struct handle *h, hid_t reqh, size_t readcap) { - if (h->reqh > 0) { - // TODO queue - _sys_fs_respond(reqh, NULL, -1, 0); - return; - } - if (h->type == H_UDP && h->udp.rx) { - _sys_fs_respond(reqh, h->udp.rx->buf, h->udp.rx->len, 0); - h->udp.rx = h->udp.rx->next; - free(h->udp.rx); - return; - } - h->reqh = reqh; - if (h->type == H_TCP) { - h->tcp.readcap = readcap; - tcp_recv_callback(h); - } -} - -static void fs_open(hid_t reqh, char *path, int flags) { -#define respond(buf, val) do{ _sys_fs_respond(reqh, buf, val, 0); return; }while(0) - struct handle *h; - if (*path != '/') respond(NULL, -1); - path++; - - if (strcmp(path, "raw") == 0) { - h = malloc(sizeof *h); - memset(h, 0, sizeof *h); - h->type = H_ETHER; - respond(h, 0); - } else if (strcmp(path, "arp") == 0) { - h = malloc(sizeof *h); - memset(h, 0, sizeof *h); - h->type = H_ARP; - respond(h, 0); - } - - /* everything below ends up sending packets */ - if (!OPEN_WRITEABLE(flags)) - respond(NULL, -EACCES); - - char *save; - const char *verb, *proto, *port_s; - uint32_t srcip, dstip; - - verb = strtok_r(path, "/", &save); - if (!verb) respond(NULL, -1); - - if (ip_parse(strtok_r(NULL, "/", &save), &srcip) < 0) - respond(NULL, -1); - if (srcip != 0) { - eprintf("unimplemented"); - respond(NULL, -1); - } - - if (strcmp(verb, "listen") == 0) { - proto = strtok_r(NULL, "/", &save); - if (!proto) respond(NULL, -1); - if (strcmp(proto, "udp") == 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_UDP; - h->reqh = reqh; - udp_listen(port, udp_listen_callback, udp_recv_callback, h); - return; - } - } - 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->reqh = reqh; - tcp_listen(port, tcp_listen_callback, tcp_recv_callback, tcp_close_callback, h); - return; - } - } - } else if (strcmp(verb, "connect") == 0) { - if (ip_parse(strtok_r(NULL, "/", &save), &dstip) < 0) - 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) { - uint16_t port = strtol(port_s, NULL, 0); - h = malloc(sizeof *h); - memset(h, 0, sizeof *h); - h->type = H_UDP; - h->udp.c = udpc_new((struct udp){ - .dst = port, - .ip.dst = dstip, - }, udp_recv_callback, h); - if (h->udp.c) { - respond(h, 0); - } else { - free(h); - respond(NULL, -1); - } - } - } - } - respond(NULL, -1); -#undef respond -} - -void fs_thread(void *arg) { (void)arg; - const size_t buflen = 4096; - char *buf = malloc(buflen); - for (;;) { - struct ufs_request res; - hid_t reqh = _sys_fs_wait(buf, buflen, &res); - if (reqh < 0) break; - struct handle *h = res.id; - long ret; - switch (res.op) { - case VFSOP_OPEN: - if (res.len < buflen) { - buf[res.len] = '\0'; - fs_open(reqh, buf, res.flags); - } else { - _sys_fs_respond(reqh, NULL, -1, 0); - } - break; - case VFSOP_READ: - if (h->dead) { - _sys_fs_respond(reqh, NULL, -ECONNRESET, 0); - break; - } - switch (h->type) { - case H_ETHER: { - struct ethq *qe; - qe = malloc(sizeof *qe); - qe->h = reqh; - qe->next = ether_queue; - ether_queue = qe; - break;} - case H_TCP: - case H_UDP: - recv_enqueue(h, reqh, res.capacity); - break; - case H_ARP: - arp_fsread(reqh, res.offset); - break; - default: - _sys_fs_respond(reqh, NULL, -1, 0); - } - break; - case VFSOP_WRITE: - if (h->dead) { - _sys_fs_respond(reqh, NULL, -ECONNRESET, 0); - break; - } - switch (h->type) { - case H_ETHER: - ret = _sys_write(state.raw_h, buf, res.len, 0, 0); - _sys_fs_respond(reqh, NULL, ret, 0); - break; - case H_TCP: - tcpc_send(h->tcp.c, buf, res.len); - _sys_fs_respond(reqh, NULL, res.len, 0); - break; - case H_UDP: - udpc_send(h->udp.c, buf, res.len); - _sys_fs_respond(reqh, NULL, res.len, 0); - break; - case H_ARP: - _sys_fs_respond(reqh, NULL, arp_fswrite(buf, res.len, res.offset), 0); - break; - default: - _sys_fs_respond(reqh, NULL, -1, 0); - } - break; - case VFSOP_CLOSE: - // TODO remove entries in queue - // TODO why does close even have _sys_fs_respond? - if (h->type == H_TCP) tcpc_close(h->tcp.c); - if (h->type == H_UDP) udpc_close(h->udp.c); - free(h); - _sys_fs_respond(reqh, NULL, -1, 0); - break; - default: - _sys_fs_respond(reqh, NULL, -1, 0); - break; - } - } - free(buf); -} diff --git a/src/user/app/netstack/icmp.c b/src/user/app/netstack/icmp.c deleted file mode 100644 index 0c6a502..0000000 --- a/src/user/app/netstack/icmp.c +++ /dev/null @@ -1,34 +0,0 @@ -#include "proto.h" -#include "util.h" - -enum { - Type = 0, - Code = 1, - Checksum = 2, - Payload = 4, -}; - -void icmp_parse(const uint8_t *buf, size_t len, struct ipv4 ip) { - if (len < Payload) return; - uint8_t type = buf[Type]; - if (type == 8 && ip.dst == state.ip) { - /* echo reply */ - icmp_send(buf + Payload, len - Payload, (struct icmp){ - .type = 0, - .ip.dst = ip.src, - .ip.e.dst = ip.e.src, - }); - } -} - -void icmp_send(const void *payload, size_t len, struct icmp i) { - i.ip.proto = 1; - uint8_t *pkt = malloc(Payload + len); - pkt[Type] = i.type; - pkt[Code] = i.code; - memcpy(pkt + Payload, payload, len); - nput16(pkt + Checksum, 0); - nput16(pkt + Checksum, ip_checksum(pkt, Payload + len)); - ipv4_send(pkt, Payload + len, i.ip); - free(pkt); -} diff --git a/src/user/app/netstack/ipv4.c b/src/user/app/netstack/ipv4.c deleted file mode 100644 index 1336dc1..0000000 --- a/src/user/app/netstack/ipv4.c +++ /dev/null @@ -1,216 +0,0 @@ -#include "proto.h" -#include "util.h" -#include -#include - -enum { - Version = 0, - HdrLen = 0, - TotalLen = 2, - Id = 4, - FragInfo = 6, - EvilBit = 0x8000, - DontFrag = 0x4000, - MoreFrags = 0x2000, - FragOff = 0x1FFF, - TTL = 8, - Proto = 9, - Checksum = 10, - SrcIP = 12, - DstIP = 16, -}; -static void ipv4_dispatch(const uint8_t *buf, size_t len, struct ipv4 ip); - -struct fragment { - struct fragment *next; /* sorted */ - size_t len, offset; - bool last; - uint8_t buf[]; -}; -struct fragmented { - /* src, dst, proto, id come from the first arrived packet - * and are used to tell fragmenteds apart. - * the rest comes from the sequentially first packet. - * ip.h.header points to a malloc'd buffer*/ - struct ipv4 h; - - struct fragment *first; - struct fragmented *next, **prev; /* *(inc->prev) == inc */ - // TODO timer -}; -struct fragmented *fragmenteds; -static struct fragmented *fragmented_find(struct ipv4 fraghdr); -static void fragmented_tryinsert(const uint8_t *payload, size_t plen, struct ipv4 ip); -static void fragmented_tryfinish(struct fragmented *inc); -static void fragmented_free(struct fragmented *inc); - -static struct fragmented *fragmented_find(struct ipv4 fraghdr) { - struct fragmented *inc; - for (inc = fragmenteds; inc; inc = inc->next) { - if (inc->h.src == fraghdr.src && - inc->h.dst == fraghdr.dst && - inc->h.proto == fraghdr.proto && - inc->h.id == fraghdr.id) - { - return inc; - } - } - inc = malloc(sizeof *inc); - memset(inc, 0, sizeof *inc); - inc->h.src = fraghdr.src; - inc->h.dst = fraghdr.dst; - inc->h.proto = fraghdr.proto; - inc->h.id = fraghdr.id; - - inc->next = fragmenteds; - if (inc->next) inc->next->prev = &inc->next; - inc->prev = &fragmenteds; - *inc->prev = inc; - return inc; -} - -static void fragmented_tryinsert(const uint8_t *payload, size_t plen, struct ipv4 ip) { - struct fragmented *inc = fragmented_find(ip); - size_t off = (ip.fraginfo & FragOff) * 8; - bool last = !(ip.fraginfo & MoreFrags); - // eprintf("fragmented packet, %u + %u, part of 0x%x", off, plen, inc); - - /* find the first fragment at a bigger offset, and insert before it */ - struct fragment **insert = &inc->first; - for (; *insert; insert = &(*insert)->next) { - if ((*insert)->offset > off) break; - if ((*insert)->offset == off) return; /* duplicate packet */ - } - /* later on: frag->next = *insert; - * if we're the last fragment, frag->next must == NULL */ - if (last && *insert != NULL) return; - - struct fragment *frag = malloc(sizeof(struct fragment) + plen); - frag->next = *insert; - *insert = frag; - frag->len = plen; - frag->offset = off; - frag->last = last; - memcpy(frag->buf, payload, plen); - - if (off == 0) { /* save header */ - assert(!inc->h.header); - void *headercpy = malloc(ip.hlen); - memcpy(headercpy, ip.header, ip.hlen); - inc->h = ip; - inc->h.header = headercpy; - } - - fragmented_tryfinish(inc); -} - -static void fragmented_tryfinish(struct fragmented *inc) { - if (inc->first->offset != 0) return; - for (struct fragment *iter = inc->first; iter; iter = iter->next) { - size_t iterend = iter->offset + iter->len; - struct fragment *next = iter->next; - if (next) { - if (iterend < next->offset) return; /* incomplete */ - if (iterend > next->offset) { - fragmented_free(inc); - return; - } - } else if (iter->last) { - void *buf = malloc(iterend); - for (struct fragment *iter = inc->first; iter; iter = iter->next) { - assert(iter->offset + iter->len <= iterend); - memcpy(buf + iter->offset, iter->buf, iter->len); - } - ipv4_dispatch(buf, iterend, inc->h); - free(buf); - fragmented_free(inc); - } - } -} - -static void fragmented_free(struct fragmented *inc) { - if (inc->next) { - inc->next->prev = inc->prev; - *inc->next->prev = inc->next; - } else { - *inc->prev = NULL; - } - - for (struct fragment *next, *iter = inc->first; iter; iter = next) { - next = iter->next; - free(iter); - } - free((void*)inc->h.header); - free(inc); -} - - -static void ipv4_dispatch(const uint8_t *buf, size_t len, struct ipv4 ip) { - switch (ip.proto) { - case 0x01: icmp_parse(buf, len, ip); break; - case 0x06: tcp_parse(buf, len, ip); break; - case 0x11: udp_parse(buf, len, ip); break; - } -} - -void ipv4_parse(const uint8_t *buf, size_t len, struct ethernet ether) { - uint8_t version, headerlen; - uint16_t totallen; - - version = buf[Version] >> 4; - if (version != 4) return; - headerlen = (buf[HdrLen] & 0xf) * 4; - totallen = nget16(buf + TotalLen); - if (totallen < headerlen) return; - - /* ignores checksum. TODO? */ - - struct ipv4 ip = (struct ipv4){ - .e = ether, - .src = nget32(buf + SrcIP), - .dst = nget32(buf + DstIP), - .id = nget16(buf + Id), - .fraginfo = nget16(buf + FragInfo), - .proto = buf[Proto], - .header = buf, - .hlen = headerlen, - }; - - if (ip.fraginfo & ~(EvilBit | DontFrag)) { - fragmented_tryinsert(buf + headerlen, totallen - headerlen, ip); - } else { - if (totallen > len) return; - ipv4_dispatch(buf + headerlen, totallen - headerlen, ip); - } -} - -static uint16_t next_id = 0; -void ipv4_send(const void *payload, size_t len, struct ipv4 ip) { - const size_t mtu = 1500; - const size_t hdrlen = 20; - - ip.e.type = ET_IPv4; - if (!ip.src) ip.src = state.ip; - if (!ip.e.dst && ip.dst == 0xFFFFFFFF) - ip.e.dst = &MAC_BROADCAST; - - uint16_t id = next_id++; - for (size_t off = 0, fraglen = mtu - hdrlen; off < len; off += fraglen) { - if (fraglen > len - off) - fraglen = len - off; - bool last = off + fraglen >= len; - uint8_t *pkt = ether_start(hdrlen + fraglen, ip.e); - pkt[Version] = 0x40; - pkt[HdrLen] |= hdrlen / 4; - nput16(pkt + TotalLen, hdrlen + fraglen); - nput16(pkt + Id, id); - nput16(pkt + FragInfo, (off >> 3) | (last ? 0 : MoreFrags)); - pkt[TTL] = 0xFF; - pkt[Proto] = ip.proto; - nput32(pkt + SrcIP, ip.src); - nput32(pkt + DstIP, ip.dst); - nput16(pkt + Checksum, ip_checksum(pkt, hdrlen)); - memcpy(pkt + hdrlen, payload + off, fraglen); - ether_finish(pkt); - } -} diff --git a/src/user/app/netstack/netstack.c b/src/user/app/netstack/netstack.c deleted file mode 100644 index 2636429..0000000 --- a/src/user/app/netstack/netstack.c +++ /dev/null @@ -1,53 +0,0 @@ -#include "proto.h" -#include "util.h" -#include -#include -#include -#include -#include -#include -#include - -struct net_state state = { - // TODO dynamically get mac - .mac = {0x52, 0x54, 0x00, 0xCA, 0x77, 0x1A}, -}; - -void network_thread(void *arg) { (void)arg; - const size_t buflen = 4096; - char *buf = malloc(buflen); - for (;;) { - long ret = _sys_read(state.raw_h, buf, buflen, -1); - if (ret < 0) break; - ether_parse((void*)buf, ret); - } - free(buf); -} - -void fs_thread(void *arg); - -int main(int argc, char **argv) { - if (argc < 4) { - eprintf("usage: netstack iface ip gateway"); - return 1; - } - state.raw_h = camellia_open(argv[1], OPEN_RW); - if (state.raw_h < 0) { - eprintf("couldn't open %s", argv[1]); - return 1; - } - if (ip_parse(argv[2], &state.ip) < 0) { - eprintf("invalid ip"); - return -1; - } - if (ip_parse(argv[3], &state.gateway) < 0) { - eprintf("invalid gateway"); - return -1; - } - setproctitle(argv[2]); - arp_request(state.gateway); - thread_create(0, network_thread, NULL); - thread_create(0, fs_thread, NULL); - _sys_await(); - return 0; -} diff --git a/src/user/app/netstack/proto.h b/src/user/app/netstack/proto.h deleted file mode 100644 index 8ea11ac..0000000 --- a/src/user/app/netstack/proto.h +++ /dev/null @@ -1,107 +0,0 @@ -#pragma once -#include -#include -#include - -typedef uint8_t mac_t[6]; -static const mac_t MAC_BROADCAST = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - -extern struct net_state { - mac_t mac; - uint32_t ip, gateway; - - hid_t raw_h; -} state; - -enum { /* ethertype */ - ET_IPv4 = 0x800, - ET_ARP = 0x806, -}; - -struct ethernet { - const mac_t *src, *dst; - uint16_t type; -}; - -struct ipv4 { - struct ethernet e; - uint32_t src, dst; - uint16_t id, fraginfo; - uint8_t proto; - const uint8_t *header; size_t hlen; -}; - -struct tcp { - struct ipv4 ip; - uint16_t src, dst; -}; - -struct udp { - struct ipv4 ip; - uint16_t src, dst; -}; - -struct icmp { - struct ipv4 ip; - uint8_t type, code; -}; - - -/* NOT THREADSAFE, YET USED FROM CONCURRENT THREADS - * will break if i implement a scheduler*/ -struct ethq { - struct ethq *next; - hid_t h; -}; -extern struct ethq *ether_queue; - -void arp_parse(const uint8_t *buf, size_t len); -void arp_request(uint32_t ip); -/* 0 on success, -1 on failure */ -int arpcache_get(uint32_t ip, mac_t *mac); -void arp_fsread(hid_t h, long offset); -long arp_fswrite(const char *buf, long len, long offset); - -void icmp_parse(const uint8_t *buf, size_t len, struct ipv4 ip); -void icmp_send(const void *payload, size_t len, struct icmp i); - -void ipv4_parse(const uint8_t *buf, size_t len, struct ethernet ether); -void ipv4_send(const void *payload, size_t len, struct ipv4 ip); - -void ether_parse(const uint8_t *buf, size_t len); -uint8_t *ether_start(size_t len, struct ethernet ether); -void ether_finish(uint8_t *pkt); - -struct udp_conn; -void udp_parse(const uint8_t *buf, size_t len, struct ipv4 ip); -/* calls callback once, after a client connects. */ -void udp_listen( - uint16_t port, - void (*on_conn)(struct udp_conn *, void *carg), - void (*on_recv)(const void *, size_t, void *carg), - void *carg); -struct udp_conn *udpc_new( - struct udp u, - void (*on_recv)(const void *, size_t, void *carg), - void *carg); -// TODO udp_onclosed -void udpc_send(struct udp_conn *, const void *buf, size_t len); -/* frees */ -void udpc_close(struct udp_conn *); - -struct tcp_conn; -void tcp_parse(const uint8_t *buf, size_t len, struct ipv4 ip); -void tcp_listen( - uint16_t port, - void (*on_conn)(struct tcp_conn *, void *carg), - 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 deleted file mode 100644 index d1adeab..0000000 --- a/src/user/app/netstack/tcp.c +++ /dev/null @@ -1,268 +0,0 @@ -/* Welcome to spaghetti land. - * This is anything but production quality. It's throwaway code, meant - * only to see how networking could fit into the architecture of the - * system. */ -#include "proto.h" -#include "util.h" -#include -#include - -enum { - SrcPort = 0, - DstPort = 2, - Seq = 4, - AckNum = 8, /* last processed seq + 1 */ - Flags = 12, - FlagSize = 0xF000, /* size of header / 4 bytes */ - /* 3 bits: 0, still unused - * 3 bits: modern stuff not in the original RFC */ - FlagURG = 0x0020, /* urgent */ - FlagACK = 0x0010, - FlagPSH = 0x0008, /* force buffer flush */ - FlagRST = 0x0004, /* reset connection */ - FlagSYN = 0x0002, /* first packet; sync sequence numbers */ - FlagFIN = 0x0001, /* last packet */ - FlagAll = 0x003F, - WinSize = 14, /* amount of data we're willing to receive */ - Checksum = 16, - Urgent = 18, - MinHdr = 20, -}; - -enum tcp_state { - LISTEN, - SYN_SENT, - SYN_RCVD, - ESTABILISHED, - LAST_ACK, - CLOSED, -}; - -struct tcp_conn { - uint32_t lip, rip; - mac_t rmac; - uint16_t lport, rport; - struct tcp_conn *next, **link; - - enum tcp_state state; - uint32_t lack, rack; - uint32_t lseq; - bool uclosed; /* did the user close? */ - - void (*on_conn)(struct tcp_conn *, void *carg); - void (*on_recv)(void *carg); - void (*on_close)(void *carg); - void *carg; - - ring_t rx; -}; -static struct tcp_conn *conns; -static void conns_append(struct tcp_conn *c) { - c->next = conns; - if (c->next) - c->next->link = &c->next; - c->link = &conns; - *c->link = c; -} -static void tcpc_sendraw(struct tcp_conn *c, uint16_t flags, const void *buf, size_t len) { - uint8_t *pkt = malloc(MinHdr + len); - memset(pkt, 0, MinHdr); - - nput16(pkt + SrcPort, c->lport); - nput16(pkt + DstPort, c->rport); - nput32(pkt + Seq, c->lseq); - c->lseq += len; - nput32(pkt + AckNum, c->lack); - flags |= (MinHdr / 4) << 12; - nput16(pkt + Flags, flags); - nput16(pkt + WinSize, ring_avail(&c->rx)); - memcpy(pkt + MinHdr, buf, len); - nput16(pkt + Checksum, ip_checksumphdr(pkt, MinHdr + len, c->lip, c->rip, 6)); - - ipv4_send(pkt, MinHdr + len, (struct ipv4){ - .proto = 6, - .src = c->lip, - .dst = c->rip, - .e.dst = &c->rmac, - }); - free(pkt); -} -void tcp_listen( - uint16_t port, - void (*on_conn)(struct tcp_conn *, void *carg), - 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->lport = port; - c->lip = state.ip; - c->state = LISTEN; - c->on_conn = on_conn; - c->on_recv = on_recv; - c->on_close = on_close; - c->carg = carg; - // TODO setting the ring size super low loses every nth byte. probably a bug with ring_t itself! - 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 wait for ARP reply - arp_request(c->rip); - if (arpcache_get(state.gateway, &c->rmac) < 0) { - eprintf("neither target nor gateway not in ARP cache, dropping"); - 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); - c->lseq++; - 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); -} -void tcpc_send(struct tcp_conn *c, const void *buf, size_t len) { - tcpc_sendraw(c, FlagACK | FlagPSH, buf, len); -} -static void tcpc_tryfree(struct tcp_conn *c) { - if (c->state == CLOSED && c->uclosed) { - if (c->next) c->next->link = c->link; - *c->link = c->next; - free(c->rx.buf); - free(c); - } -} -void tcpc_close(struct tcp_conn *c) { - /* ONLY FOR USE BY THE USER, drops their reference */ - assert(!c->uclosed); - c->uclosed = true; - if (c->state != CLOSED && c->state != LAST_ACK && c->state != LISTEN) { - tcpc_sendraw(c, FlagFIN | FlagACK, NULL, 0); - c->state = LAST_ACK; - c->on_conn = NULL; - c->on_close = NULL; - } - tcpc_tryfree(c); -} - -void tcp_parse(const uint8_t *buf, size_t len, struct ipv4 ip) { - if (len < 20) return; - uint16_t srcport = nget16(buf + SrcPort); - uint16_t dstport = nget16(buf + DstPort); - uint32_t seq = nget32(buf + Seq); - uint32_t acknum = nget32(buf + AckNum); - uint16_t flags = nget16(buf + Flags); - // uint16_t winsize = nget16(buf + WinSize); - // uint16_t chksum = nget16(buf + Checksum); - uint16_t hdrlen = ((flags & FlagSize) >> 12) * 4; - if (hdrlen > len) return; - uint16_t payloadlen = len - hdrlen; - - for (struct tcp_conn *iter = conns; iter; iter = iter->next) { - if (iter->state == CLOSED) continue; - if (iter->lport != dstport) continue; - - if (iter->state == LISTEN && (flags & FlagAll) == FlagSYN) { - iter->state = SYN_RCVD; - iter->rip = ip.src; - iter->rport = srcport; - iter->lack = seq + 1; - memcpy(&iter->rmac, ip.e.src, sizeof(mac_t)); - tcpc_sendraw(iter, FlagSYN | FlagACK, NULL, 0); - iter->lseq++; - if (iter->on_conn) iter->on_conn(iter, iter->carg); - return; - } - - 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; - if (iter->state == LAST_ACK) { - // TODO check if ack has correct number - iter->state = CLOSED; - tcpc_tryfree(iter); - // TODO free (also after a timeout) - return; - } - } - if (iter->lack != seq && iter->lack - 1 != seq) { - eprintf("remote seq jumped by %d", seq - iter->lack); - tcpc_sendraw(iter, FlagACK, NULL, 0); - return; - } - // TODO check if overflows window size - if (payloadlen) { - iter->lack = seq + payloadlen; - ring_put(&iter->rx, buf + hdrlen, payloadlen); - if (iter->on_recv) iter->on_recv(iter->carg); - tcpc_sendraw(iter, FlagACK, NULL, 0); - } - if (flags & FlagFIN) { - // TODO should resend the packet until an ACK is received - // TODO duplicated in tcpc_close - tcpc_sendraw(iter, FlagFIN | FlagACK, NULL, 0); - iter->state = LAST_ACK; - if (iter->on_close) iter->on_close(iter->carg); - return; - } - return; - } - } - - if ((flags & FlagRST) == 0) { - uint8_t *pkt = malloc(MinHdr); - memset(pkt, 0, MinHdr); - nput16(pkt + SrcPort, dstport); - nput16(pkt + DstPort, srcport); - nput32(pkt + Seq, acknum); - nput32(pkt + AckNum, seq + 1); - uint16_t pktflags = FlagRST | FlagACK; - pktflags |= (MinHdr / 4) << 12; - nput16(pkt + Flags, pktflags); - nput16(pkt + Checksum, ip_checksumphdr(pkt, MinHdr, ip.src, ip.dst, 6)); - - ipv4_send(pkt, MinHdr, (struct ipv4){ - .proto = 6, - .src = ip.dst, - .dst = ip.src, - .e.dst = ip.e.src, - }); - free(pkt); - } -} diff --git a/src/user/app/netstack/udp.c b/src/user/app/netstack/udp.c deleted file mode 100644 index 3d560ae..0000000 --- a/src/user/app/netstack/udp.c +++ /dev/null @@ -1,124 +0,0 @@ -#include "proto.h" -#include "util.h" - -enum { - SrcPort = 0, - DstPort = 2, - Length = 4, - Checksum = 6, - Payload = 8, -}; - - -struct udp_conn { - uint32_t lip, rip; - uint16_t lport, rport; - mac_t rmac; - void (*on_conn)(struct udp_conn *, void *); /* if non-NULL - listening, if NULL - estabilished */ - void (*on_recv)(const void *, size_t, void *); - void *carg; - struct udp_conn *next, **link; -}; -static struct udp_conn *conns; -static void conns_append(struct udp_conn *c) { - c->next = conns; - if (c->next) - c->next->link = &c->next; - c->link = &conns; - *c->link = c; -} -void udp_listen( - uint16_t port, - void (*on_conn)(struct udp_conn *, void *carg), - void (*on_recv)(const void *, size_t, void *carg), - void *carg) -{ - if (!on_conn) return; - struct udp_conn *c = malloc(sizeof *c); - c->lport = port; - c->lip = state.ip; - c->on_conn = on_conn; - c->on_recv = on_recv; - c->carg = carg; - conns_append(c); -} -struct udp_conn *udpc_new( - struct udp u, - void (*on_recv)(const void *, size_t, void *carg), - void *carg) -{ - struct udp_conn *c = malloc(sizeof *c); - memset(c, 0, sizeof *c); - c->lip = u.ip.src; - c->rip = u.ip.dst; - c->lport = u.src ? u.src : 50000; // TODO randomize source ports - c->rport = u.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->on_recv = on_recv; - c->carg = carg; - conns_append(c); - return c; -} -void udpc_send(struct udp_conn *c, const void *buf, size_t len) { - uint8_t *pkt = malloc(Payload + len); - nput16(pkt + SrcPort, c->lport); - nput16(pkt + DstPort, c->rport); - nput16(pkt + Length, Payload + len); - nput16(pkt + Checksum, 0); - memcpy(pkt + Payload, buf, len); - ipv4_send(pkt, Payload + len, (struct ipv4){ - .proto = 0x11, - .src = c->lip, - .dst = c->rip, - .e.dst = &c->rmac, - }); - free(pkt); -} -void udpc_close(struct udp_conn *c) { - if (c->next) c->next->link = c->link; - *(c->link) = c->next; - free(c); -} - - -void udp_parse(const uint8_t *buf, size_t len, struct ipv4 ip) { - uint16_t srcport = nget16(buf + SrcPort); - uint16_t dstport = nget16(buf + DstPort); - bool active = false; - - for (struct udp_conn *iter = conns; iter; iter = iter->next) { - if (iter->on_conn && dstport == iter->lport) { - iter->on_conn(iter, iter->carg); - iter->on_conn = NULL; - iter->rport = srcport; - memcpy(&iter->rmac, ip.e.src, sizeof(mac_t)); - iter->rip = ip.src; - } - if (iter->rip == ip.src && - iter->rport == srcport && - iter->lport == dstport && - iter->on_recv) - { - active = true; - iter->on_recv(buf + Payload, len - Payload, iter->carg); - } - } - - if (!active) { - uint8_t *pkt = malloc(4 + ip.hlen + 8); - nput32(pkt, 0); - memcpy(pkt + 4, ip.header, ip.hlen + 8); - icmp_send(pkt, 4 + ip.hlen + 8, (struct icmp){ - .type = 3, /* destination unreachable */ - .code = 3, /* port unreachable */ - .ip.dst = ip.src, - .ip.e.dst = ip.e.src, - }); - free(pkt); - } -} diff --git a/src/user/app/netstack/util.c b/src/user/app/netstack/util.c deleted file mode 100644 index 68092aa..0000000 --- a/src/user/app/netstack/util.c +++ /dev/null @@ -1,60 +0,0 @@ -#include "util.h" - -/* https://www.w3.org/TR/PNG/#D-CRCAppendix */ -static uint32_t crc_table[256]; -uint32_t crc32(const uint8_t *buf, size_t len) { - if (!crc_table[1]) { - for (int i = 0; i < 256; i++) { - uint32_t c = i; - for (int j = 0; j < 8; j++) - c = ((c&1) ? 0xedb88320 : 0) ^ (c >> 1); - crc_table[i] = c; - } - } - - uint32_t c = 0xFFFFFFFF; - for (size_t i = 0; i < len; i++) - c = crc_table[(c ^ buf[i]) & 0xff] ^ (c >> 8); - return ~c; -} - -uint16_t ip_checksum(const uint8_t *buf, size_t len) { - uint32_t c = 0; - while (len >= 2) { - c += nget16(buf); - buf += 2; len -= 2; - } - if (len) c += (*buf) << 8; - while (c > 0xFFFF) c = (c & 0xFFFF) + (c >> 16); - return ~c; -} - -uint16_t ip_checksumphdr( - const uint8_t *buf, size_t len, - uint32_t ip1, uint32_t ip2, - uint16_t proto) -{ - uint32_t c = (uint16_t)~ip_checksum(buf, len); - c += (ip1 & 0xFFFF) + (ip1 >> 16); - c += (ip2 & 0xFFFF) + (ip2 >> 16); - c += proto + len; - while (c > 0xFFFF) c = (c & 0xFFFF) + (c >> 16); - return ~c; -} - -int ip_parse(const char *s, uint32_t *dest) { - if (!s) return -1; - - uint32_t ip = strtol(s, (char**)&s, 0); - int parts = 1; - for (; parts < 4; parts++) { - if (!*s) break; - if (*s++ != '.') return -1; - ip <<= 8; - ip += strtol(s, (char**)&s, 0); - } - if (parts > 1) - ip = ((ip & 0xFFFFFF00) << 8 * (4 - parts)) | (ip & 0xFF); - *dest = ip; - return 0; -} diff --git a/src/user/app/netstack/util.h b/src/user/app/netstack/util.h deleted file mode 100644 index 0b29560..0000000 --- a/src/user/app/netstack/util.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once -#include -#include -#include -#include - -#define eprintf(fmt, ...) fprintf(stderr, "netstack: "fmt"\n" __VA_OPT__(,) __VA_ARGS__) - -uint32_t crc32(const uint8_t *buf, size_t len); -uint16_t ip_checksum(const uint8_t *buf, size_t len); -uint16_t ip_checksumphdr( - const uint8_t *buf, size_t len, - uint32_t ip1, uint32_t ip2, - uint16_t proto); -/* 0 on success, negative failure */ -int ip_parse(const char *s, uint32_t *ip); - -static inline void nput16(void *vbuf, uint16_t n) { - uint8_t *b = vbuf; - b[0] = n >> 8; - b[1] = n >> 0; -} - -static inline void nput32(void *vbuf, uint32_t n) { - uint8_t *b = vbuf; - b[0] = n >> 24; - b[1] = n >> 16; - b[2] = n >> 8; - b[3] = n >> 0; -} - -static inline uint16_t nget16(const void *vbuf) { - const uint8_t *b = vbuf; - return (b[0] << 8) - | (b[1] << 0); -} - -static inline uint32_t nget32(const void *vbuf) { - const uint8_t *b = vbuf; - return (b[0] << 24) - | (b[1] << 16) - | (b[2] << 8) - | (b[3] << 0); -} -- cgit v1.2.3