summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/sbc_harness/CMakeLists.txt3
-rw-r--r--cmd/sbc_harness/hw/w5500.c145
-rw-r--r--cmd/sbc_harness/hw/w5500.h18
-rw-r--r--cmd/sbc_harness/main.c30
-rw-r--r--cmd/srv9p/gnet.c283
-rw-r--r--cmd/srv9p/gnet.h20
-rw-r--r--cmd/srv9p/main.c4
-rw-r--r--lib9p/include/lib9p/srv.h2
-rw-r--r--lib9p/srv.c14
-rw-r--r--libdhcp/dhcp.c9
-rw-r--r--libmisc/include/libmisc/hash.h31
-rw-r--r--libmisc/include/libmisc/net.h55
12 files changed, 452 insertions, 162 deletions
diff --git a/cmd/sbc_harness/CMakeLists.txt b/cmd/sbc_harness/CMakeLists.txt
index 201b378..54553f0 100644
--- a/cmd/sbc_harness/CMakeLists.txt
+++ b/cmd/sbc_harness/CMakeLists.txt
@@ -15,8 +15,9 @@ target_include_directories(sbc_harness PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/config
target_include_directories(sbc_harness PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(sbc_harness
pico_stdlib
- hardware_spi
+ hardware_flash
hardware_gpio
+ hardware_spi
libmisc
libusb
diff --git a/cmd/sbc_harness/hw/w5500.c b/cmd/sbc_harness/hw/w5500.c
index b95ad88..ab1ac19 100644
--- a/cmd/sbc_harness/hw/w5500.c
+++ b/cmd/sbc_harness/hw/w5500.c
@@ -122,7 +122,7 @@ static COROUTINE w5500_irq_cr(void *_chip) {
for (uint8_t socknum = 0; socknum < 8; socknum++) {
if (!(sockmask & (1<<socknum)))
continue;
- struct _w5500_listener *listener = &chip->listeners[socknum];
+ struct _w5500_tcp_listener *listener = &chip->listeners[socknum];
uint8_t sockintr = w5500ll_read_sock_reg(chip->spidev, socknum, interrupt);
@@ -144,19 +144,19 @@ static COROUTINE w5500_irq_cr(void *_chip) {
/* init() *********************************************************************/
-static implements_net_conn *w5500_accept(implements_net_listener *_listener);
-static ssize_t w5500_read(implements_net_conn *conn, void *buf, size_t count);
-static ssize_t w5500_write(implements_net_conn *conn, void *buf, size_t count);
-static int w5500_close(implements_net_conn *conn, bool rd, bool wr);
+static implements_net_stream_conn *w5500_tcp_accept(implements_net_stream_listener *listener);
+static ssize_t w5500_tcp_read(implements_net_stream_conn *conn, void *buf, size_t count);
+static ssize_t w5500_tcp_write(implements_net_stream_conn *conn, void *buf, size_t count);
+static int w5500_tcp_close(implements_net_stream_conn *conn, bool rd, bool wr);
-static struct net_listener_vtable w5500_listener_vtable = {
- .accept = w5500_accept,
+static struct net_stream_listener_vtable w5500_tcp_listener_vtable = {
+ .accept = w5500_tcp_accept,
};
-static struct net_conn_vtable w5500_conn_vtable = {
- .read = w5500_read,
- .write = w5500_write,
- .close = w5500_close,
+static struct net_stream_conn_vtable w5500_tcp_conn_vtable = {
+ .read = w5500_tcp_read,
+ .write = w5500_tcp_write,
+ .close = w5500_tcp_close,
};
static struct w5500 *w5500_chips[CONFIG_W5500_NUM] = {0};
@@ -183,13 +183,13 @@ void _w5500_init(struct w5500 *chip,
.next_local_port = CONFIG_W5500_LOCAL_PORT_MIN,
};
for (uint8_t i = 0; i < 8; i++) {
- chip->listeners[i] = (struct _w5500_listener){
+ chip->listeners[i] = (struct _w5500_tcp_listener){
/* const-after-init */
- .vtable = &w5500_listener_vtable,
+ .vtable = &w5500_tcp_listener_vtable,
.socknum = i,
.active_conn = {
/* const-after-init */
- .vtable = &w5500_conn_vtable,
+ .vtable = &w5500_tcp_conn_vtable,
/* mutable */
.read_open = false,
.write_open = false,
@@ -219,24 +219,44 @@ void _w5500_init(struct w5500 *chip,
/* chip methods ***************************************************************/
static inline void w5500_post_reset(struct w5500 *chip, struct net_eth_addr addr) {
+ /* The W5500 does not have a built-in MAC address, we must
+ * provide one. */
w5500ll_write_common_reg(chip->spidev, eth_addr, addr);
- /* The RP2040 needs a 1/sys_clk hysteresis between interrupts for us
- * to notice them. At the maximum-rated clock-rate of 133MHz, that
- * means 7.5ns (but the sbc-harness overclocks the RP2040, so we
- * could get away with even shorter).
+ /* The RP2040 needs a 1/sys_clk hysteresis between interrupts
+ * for us to notice them. At the maximum-rated clock-rate of
+ * 133MHz, that means 7.5ns (but the sbc-harness overclocks
+ * the RP2040, so we could get away with even shorter).
*
- * The hysteresis is (intlevel+1)*4/(150MHz) (if intlevel is
- * non-zero), or (intlevel+1)*26.7ns; so even the shortest-possible
- * hysteresis much larger than necessary for us. */
+ * If intlevel is non-zero, then the hysteresis is
+ * (intlevel+1)*4/(150MHz), or (intlevel+1)*26.7ns; so even
+ * the shortest-possible hysteresis much larger than necessary
+ * for us. */
w5500ll_write_common_reg(chip->spidev, intlevel, uint16be_marshal(1));
- /* This implementation does not care about any of the chip-level
- * interrupts. */
+ /* This implementation does not care about any of the
+ * chip-level interrupts. */
w5500ll_write_common_reg(chip->spidev, chip_interrupt_mask, 0);
- /* This implementation cares about interrupts for each socket. */
+ /* This implementation cares about interrupts for each
+ * socket. */
w5500ll_write_common_reg(chip->spidev, sock_interrupt_mask, 0xFF);
+
+ /* Configure retry/timeout.
+ *
+ * timeout_arp = 0.1ms * retry_time * (retry_count+1)
+ *
+ * retry_count
+ * timeout_tcp = 0.1ms * retry_time * Σ 2^min(n, floor(1+log_2(65535/retry_time)))
+ * n=0
+ *
+ * For retry_time=2000, retry_count=3, this means
+ *
+ * timeout_arp = 0.8s
+ * timeout_tcp = 3.0s
+ */
+ w5500ll_write_common_reg(chip->spidev, retry_time, uint16be_marshal(2000));
+ w5500ll_write_common_reg(chip->spidev, retry_count, 3);
}
void w5500_hard_reset(struct w5500 *chip, struct net_eth_addr addr) {
@@ -263,8 +283,8 @@ void w5500_netcfg(struct w5500 *chip, struct w5500_netcfg cfg) {
w5500ll_write_common_reg(chip->spidev, ip_addr, cfg.addr);
}
-implements_net_listener *w5500_listen(struct w5500 *chip, uint8_t socknum,
- uint16_t port) {
+implements_net_stream_listener *w5500_tcp_listen(struct w5500 *chip, uint8_t socknum,
+ uint16_t port) {
assert(chip);
assert(socknum < 8);
assert(port);
@@ -275,13 +295,13 @@ implements_net_listener *w5500_listen(struct w5500 *chip, uint8_t socknum,
return &chip->listeners[socknum];
}
-/* listener methods ***********************************************************/
+/* tcp_listener methods *******************************************************/
-static struct w5500 *w5500_listener_chip(struct _w5500_listener *listener) {
+static struct w5500 *w5500_tcp_listener_chip(struct _w5500_tcp_listener *listener) {
assert(listener);
assert(listener->socknum < 8);
- struct _w5500_listener *sock0 = &listener[-listener->socknum];
+ struct _w5500_tcp_listener *sock0 = &listener[-listener->socknum];
assert(sock0);
struct w5500 *chip =
((void *)sock0) - offsetof(struct w5500, listeners);
@@ -289,9 +309,9 @@ static struct w5500 *w5500_listener_chip(struct _w5500_listener *listener) {
return chip;
}
-static inline void w5500_listener_cmd(struct _w5500_listener *listener, uint8_t cmd) {
+static inline void w5500_tcp_listener_cmd(struct _w5500_tcp_listener *listener, uint8_t cmd) {
assert(listener);
- struct w5500 *chip = w5500_listener_chip(listener);
+ struct w5500 *chip = w5500_tcp_listener_chip(listener);
uint8_t socknum = listener->socknum;
cr_mutex_lock(&listener->cmd_mu);
@@ -301,12 +321,12 @@ static inline void w5500_listener_cmd(struct _w5500_listener *listener, uint8_t
cr_mutex_unlock(&listener->cmd_mu);
}
-static inline void w5500_listener_cmd_close(struct _w5500_listener *listener) {
+static inline void w5500_tcp_listener_cmd_close(struct _w5500_tcp_listener *listener) {
assert(listener);
- struct w5500 *chip = w5500_listener_chip(listener);
+ struct w5500 *chip = w5500_tcp_listener_chip(listener);
uint8_t socknum = listener->socknum;
- w5500_listener_cmd(listener, CMD_CLOSE);
+ w5500_tcp_listener_cmd(listener, CMD_CLOSE);
w5500ll_write_sock_reg(chip->spidev, socknum, interrupt, 0xFF);
while (w5500ll_read_sock_reg(chip->spidev, socknum, state) != STATE_CLOSED)
cr_yield();
@@ -314,27 +334,27 @@ static inline void w5500_listener_cmd_close(struct _w5500_listener *listener) {
listener->active_conn.read_open = listener->active_conn.write_open = false;
}
-#define ASSERT_LISTENER() \
- struct _w5500_listener *self = \
- VCALL_SELF(struct _w5500_listener, \
- implements_net_listener, _self); \
- struct w5500 *chip = w5500_listener_chip(self); \
+#define ASSERT_LISTENER() \
+ struct _w5500_tcp_listener *self = \
+ VCALL_SELF(struct _w5500_tcp_listener, \
+ implements_net_stream_listener, _self); \
+ struct w5500 *chip = w5500_tcp_listener_chip(self); \
uint8_t socknum = self->socknum;
-static implements_net_conn *w5500_accept(implements_net_listener *_self) {
+static implements_net_stream_conn *w5500_tcp_accept(implements_net_stream_listener *_self) {
ASSERT_LISTENER();
restart:
/* Mimics socket.c:socket(). */
- w5500_listener_cmd_close(self);
+ w5500_tcp_listener_cmd_close(self);
w5500ll_write_sock_reg(chip->spidev, socknum, mode, SOCKMODE_TCP);
w5500ll_write_sock_reg(chip->spidev, socknum, local_port, uint16be_marshal(self->port));
- w5500_listener_cmd(self, CMD_OPEN);
+ w5500_tcp_listener_cmd(self, CMD_OPEN);
while (w5500ll_read_sock_reg(chip->spidev, socknum, state) != STATE_TCP_INIT)
cr_yield();
/* Mimics socket.c:listen(). */
- w5500_listener_cmd(self, CMD_LISTEN);
+ w5500_tcp_listener_cmd(self, CMD_LISTEN);
for (;;) {
uint8_t state = w5500ll_read_sock_reg(chip->spidev, socknum, state);
switch (state) {
@@ -356,31 +376,32 @@ static implements_net_conn *w5500_accept(implements_net_listener *_self) {
/* conn methods ***************************************************************/
-static struct _w5500_listener *w5500_conn_listener(struct _w5500_conn *conn) {
+static struct _w5500_tcp_listener *w5500_tcp_conn_listener(struct _w5500_tcp_conn *conn) {
assert(conn);
- struct _w5500_listener *list =
- ((void *)conn) - offsetof(struct _w5500_listener, active_conn);
+ struct _w5500_tcp_listener *list =
+ ((void *)conn) - offsetof(struct _w5500_tcp_listener, active_conn);
return list;
}
#define ASSERT_CONN() \
- struct _w5500_conn *self = \
- VCALL_SELF(struct _w5500_conn, implements_net_conn, _self); \
- struct _w5500_listener *listener = w5500_conn_listener(self); \
- struct w5500 *chip = w5500_listener_chip(listener); \
+ struct _w5500_tcp_conn *self = \
+ VCALL_SELF(struct _w5500_tcp_conn, implements_net_stream_conn, _self); \
+ struct _w5500_tcp_listener *listener = w5500_tcp_conn_listener(self); \
+ struct w5500 *chip = w5500_tcp_listener_chip(listener); \
uint8_t socknum = listener->socknum;
-static ssize_t w5500_write(implements_net_conn *_self, void *buf, size_t count) {
+static ssize_t w5500_tcp_write(implements_net_stream_conn *_self, void *buf, size_t count) {
ASSERT_CONN();
assert(buf);
assert(count);
- /* What we really want is to pause until we receive an ACK
- * for some data we just queued, so that we can line up some
- * new data to keep the buffer full. But that's not what SEND_FINIAIUI, the
- * SEND_FINISHED interrupt doesn't fire until we receive the
- * *last* ACK for the data, when the buffer is entirely empty.
+ /* What we really want is to pause until we receive an ACK for
+ * some data we just queued, so that we can line up some new
+ * data to keep the buffer full. But that's not what
+ * SEND_FINIAIUI, the SEND_FINISHED interrupt doesn't fire
+ * until we receive the *last* ACK for the data, when the
+ * buffer is entirely empty.
*
* Which means we basically have to busy-poll for space in the
* buffer becoming available.
@@ -416,13 +437,13 @@ static ssize_t w5500_write(implements_net_conn *_self, void *buf, size_t count)
w5500ll_write_sock_reg(chip->spidev, socknum, tx_write_pointer, uint16be_marshal(ptr+freesize));
/* Submit the queue. */
- w5500_listener_cmd(listener, CMD_SEND);
+ w5500_tcp_listener_cmd(listener, CMD_SEND);
done += freesize;
}
return done;
}
-static ssize_t w5500_read(implements_net_conn *_self, void *buf, size_t count) {
+static ssize_t w5500_tcp_read(implements_net_stream_conn *_self, void *buf, size_t count) {
ASSERT_CONN();
assert(buf);
assert(count);
@@ -452,20 +473,20 @@ static ssize_t w5500_read(implements_net_conn *_self, void *buf, size_t count) {
w5500ll_read(chip->spidev, ptr, CTL_BLOCK_SOCK(socknum, RX), &((char *)buf)[done], avail);
w5500ll_write_sock_reg(chip->spidev, socknum, rx_read_pointer, uint16be_marshal(ptr+avail));
- w5500_listener_cmd(listener, CMD_RECV);
+ w5500_tcp_listener_cmd(listener, CMD_RECV);
done += avail;
}
return done;
}
-static int w5500_close(implements_net_conn *_self, bool rd, bool wr) {
+static int w5500_tcp_close(implements_net_stream_conn *_self, bool rd, bool wr) {
ASSERT_CONN();
if (rd)
self->read_open = false;
if (wr && self->write_open) {
- w5500_listener_cmd(listener, CMD_DISCON);
+ w5500_tcp_listener_cmd(listener, CMD_DISCON);
while (self->write_open) {
uint8_t state = w5500ll_read_sock_reg(chip->spidev, socknum, state);
switch (state) {
@@ -473,7 +494,7 @@ static int w5500_close(implements_net_conn *_self, bool rd, bool wr) {
self->write_open = false;
/* Can still read */
if (!self->read_open)
- w5500_listener_cmd_close(listener);
+ w5500_tcp_listener_cmd_close(listener);
break;
case STATE_CLOSED:
self->write_open = false;
diff --git a/cmd/sbc_harness/hw/w5500.h b/cmd/sbc_harness/hw/w5500.h
index d0c8d48..cf28579 100644
--- a/cmd/sbc_harness/hw/w5500.h
+++ b/cmd/sbc_harness/hw/w5500.h
@@ -13,21 +13,19 @@
#include "hw/spi.h"
-struct _w5500_listener;
-
-struct _w5500_conn {
+struct _w5500_tcp_conn {
/* const-after-init */
- implements_net_conn;
+ implements_net_stream_conn;
/* mutable */
bool read_open;
bool write_open;
};
-struct _w5500_listener {
+struct _w5500_tcp_listener {
/* const-after-init */
- implements_net_listener;
+ implements_net_stream_listener;
uint8_t socknum;
- struct _w5500_conn active_conn;
+ struct _w5500_tcp_conn active_conn;
/* mutable */
uint16_t port;
@@ -43,7 +41,7 @@ struct w5500 {
/* mutable */
uint16_t next_local_port;
- struct _w5500_listener listeners[8];
+ struct _w5500_tcp_listener listeners[8];
cr_sema_t intr;
};
@@ -91,7 +89,7 @@ struct w5500_netcfg {
*/
void w5500_netcfg(struct w5500 *self, struct w5500_netcfg cfg);
-implements_net_listener *w5500_listen(struct w5500 *self, uint8_t socknum,
- uint16_t port);
+implements_net_stream_listener *w5500_listen(struct w5500 *self, uint8_t socknum,
+ uint16_t port);
#endif /* _HW_W5500_H_ */
diff --git a/cmd/sbc_harness/main.c b/cmd/sbc_harness/main.c
index c6df8f5..8ecc56c 100644
--- a/cmd/sbc_harness/main.c
+++ b/cmd/sbc_harness/main.c
@@ -7,9 +7,11 @@
#include <string.h> /* for strlen() */
#include <stdio.h> /* for printf() */
#include "pico/stdlib.h"
+#include "hardware/flash.h"
#include <libcr/coroutine.h>
#include <libusb/usb_common.h>
+#include <libmisc/hash.h>
#include "hw/rp2040_hwspi.h"
#include "hw/w5500.h"
@@ -32,9 +34,23 @@ COROUTINE hello_world_cr(void *_chan) {
}
int main() {
- /* initialization */
+ /* initialization *****************************************************/
stdio_uart_init();
+ /* NOR flash chips have a (bog-?)standard "RUID" "Read Unique
+ * ID" instruction; use our flash chip's unique ID as the
+ * basis for our serial numbers. */
+ uint64_t flash_id64;
+ static_assert(sizeof(flash_id64) == FLASH_UNIQUE_ID_SIZE_BYTES);
+ flash_get_unique_id((uint8_t *)&flash_id64);
+ uint32_t flash_id32 = hash(&flash_id64, sizeof(flash_id64));
+ static_assert(sizeof(flash_id32) == sizeof(hash(NULL, 0)));
+ uint8_t flash_id24[3] = {
+ (uint8_t)((flash_id32 >> 16) & 0xFF),
+ (uint8_t)((flash_id32 >> 8) & 0xFF),
+ (uint8_t)((flash_id32 >> 0) & 0xFF),
+ };
+
struct rp2040_hwspi dev_spi;
struct w5500 dev_w5500;
rp2040_hwspi_init(&dev_spi, "W5500", RP2040_HWSPI_0,
@@ -47,18 +63,24 @@ int main() {
w5500_init(&dev_w5500, "W5500", &dev_spi,
21, /* PIN_INTR */
20, /* PIN_RESET */
- ((struct net_eth_addr){{0xDE,0xAD,0xBE,0xEF,0x01,0x02}}));
+ ((struct net_eth_addr){{
+ /* vendor ID: "Wiznet" */
+ 0x00, 0x08, 0xDC,
+ /* serial number */
+ flash_id24[0], flash_id24[1], flash_id24[2],
+ }}));
usb_common_earlyinit();
usb_keyboard_init();
usb_common_lateinit();
- /* set up coroutines */
+ /* set up coroutines **************************************************/
coroutine_add(usb_common_cr, NULL);
usb_keyboard_rpc_t keyboard_chan = {0};
coroutine_add(usb_keyboard_cr, &keyboard_chan);
//coroutine_add(hello_world_cr, &keyboard_chan);
+ //coroutine_add(dhcp_client_cr, NULL);
- /* Event loop. */
+ /* event loop *********************************************************/
coroutine_main();
}
diff --git a/cmd/srv9p/gnet.c b/cmd/srv9p/gnet.c
index d7e8717..5dd4a93 100644
--- a/cmd/srv9p/gnet.c
+++ b/cmd/srv9p/gnet.c
@@ -70,24 +70,35 @@ static inline bool RUN_PTHREAD(void *(*fn)(void *), void *args) {
return false;
}
-/* init() ( AKA socket(3) + listen(3) )****************************************/
+static inline ssize_t gnet_map_errno(ssize_t v) {
+ if (v >= 0)
+ return v;
+ switch (v) {
+ case ETIMEDOUT:
+ return NET_ETIMEDOUT;
+ default:
+ return NET_EOTHER;
+ }
+}
+
+/* TCP init() ( AKA socket(3) + listen(3) )************************************/
-static implements_net_conn *gnet_accept(implements_net_listener *_listener);
-static ssize_t gnet_read(implements_net_conn *conn, void *buf, size_t count);
-static ssize_t gnet_write(implements_net_conn *conn, void *buf, size_t count);
-static int gnet_close(implements_net_conn *conn, bool rd, bool wr);
+static implements_net_stream_conn *gnet_tcp_accept(implements_net_stream_listener *_listener);
+static ssize_t gnet_tcp_read(implements_net_stream_conn *conn, void *buf, size_t count);
+static ssize_t gnet_tcp_write(implements_net_stream_conn *conn, void *buf, size_t count);
+static int gnet_tcp_close(implements_net_stream_conn *conn, bool rd, bool wr);
-static struct net_listener_vtable gnet_listener_vtable = {
- .accept = gnet_accept,
+static struct net_stream_listener_vtable gnet_tcp_listener_vtable = {
+ .accept = gnet_tcp_accept,
};
-static struct net_conn_vtable gnet_conn_vtable = {
- .read = gnet_read,
- .write = gnet_write,
- .close = gnet_close,
+static struct net_stream_conn_vtable gnet_tcp_conn_vtable = {
+ .read = gnet_tcp_read,
+ .write = gnet_tcp_write,
+ .close = gnet_tcp_close,
};
-void gnet_listener_init(struct gnet_listener *self, uint16_t port) {
+void gnet_tcp_listener_init(struct gnet_tcp_listener *self, uint16_t port) {
int listenerfd;
union {
struct sockaddr_in in;
@@ -108,13 +119,13 @@ void gnet_listener_init(struct gnet_listener *self, uint16_t port) {
if (listen(listenerfd, 0) < 0)
error(1, errno, "listen");
- self->vtable = &gnet_listener_vtable;
+ self->vtable = &gnet_tcp_listener_vtable;
self->fd = listenerfd;
}
-/* accept() *******************************************************************/
+/* TCP accept() ***************************************************************/
-struct _pthread_accept_args {
+struct gnet_pthread_accept_args {
pthread_t cr_thread;
cid_t cr_coroutine;
@@ -123,8 +134,8 @@ struct _pthread_accept_args {
int *ret_connfd;
};
-static void *_pthread_accept(void *_args) {
- struct _pthread_accept_args *args = _args;
+static void *gnet_pthread_accept(void *_args) {
+ struct gnet_pthread_accept_args *args = _args;
*(args->ret_connfd) = accept(args->listenerfd, NULL, NULL);
if (*(args->ret_connfd) < 0)
*(args->ret_connfd) = -errno;
@@ -132,28 +143,29 @@ static void *_pthread_accept(void *_args) {
return NULL;
};
-static implements_net_conn *gnet_accept(implements_net_listener *_listener) {
- struct gnet_listener *listener = VCALL_SELF(struct gnet_listener, implements_net_listener, _listener);
+static implements_net_stream_conn *gnet_tcp_accept(implements_net_stream_listener *_listener) {
+ struct gnet_tcp_listener *listener =
+ VCALL_SELF(struct gnet_tcp_listener, implements_net_stream_listener, _listener);
assert(listener);
int ret_connfd;
- struct _pthread_accept_args args = {
+ struct gnet_pthread_accept_args args = {
.cr_thread = pthread_self(),
.cr_coroutine = cr_getcid(),
.listenerfd = listener->fd,
.ret_connfd = &ret_connfd,
};
- if (RUN_PTHREAD(_pthread_accept, &args))
+ if (RUN_PTHREAD(gnet_pthread_accept, &args))
return NULL;
- listener->active_conn.vtable = &gnet_conn_vtable;
+ listener->active_conn.vtable = &gnet_tcp_conn_vtable;
listener->active_conn.fd = ret_connfd;
return &listener->active_conn;
}
-/* read() *********************************************************************/
+/* TCP read() *****************************************************************/
-struct _pthread_read_args {
+struct gnet_pthread_read_args {
pthread_t cr_thread;
cid_t cr_coroutine;
@@ -164,21 +176,22 @@ struct _pthread_read_args {
ssize_t *ret;
};
-static void *_pthread_read(void *_args) {
- struct _pthread_read_args *args = _args;
+static void *gnet_pthread_read(void *_args) {
+ struct gnet_pthread_read_args *args = _args;
*(args->ret) = read(args->connfd, args->buf, args->count);
if (*(args->ret) < 0)
- *(args->ret) = -errno;
+ *(args->ret) = gnet_map_errno(-errno);
WAKE_COROUTINE(args);
return NULL;
};
-static ssize_t gnet_read(implements_net_conn *_conn, void *buf, size_t count) {
- struct _gnet_conn *conn = VCALL_SELF(struct _gnet_conn, implements_net_conn, _conn);
+static ssize_t gnet_tcp_read(implements_net_stream_conn *_conn, void *buf, size_t count) {
+ struct _gnet_tcp_conn *conn =
+ VCALL_SELF(struct _gnet_tcp_conn, implements_net_stream_conn, _conn);
assert(conn);
ssize_t ret;
- struct _pthread_read_args args = {
+ struct gnet_pthread_read_args args = {
.cr_thread = pthread_self(),
.cr_coroutine = cr_getcid(),
@@ -188,14 +201,14 @@ static ssize_t gnet_read(implements_net_conn *_conn, void *buf, size_t count) {
.ret = &ret,
};
- if (RUN_PTHREAD(_pthread_read, &args))
- return -1;
+ if (RUN_PTHREAD(gnet_pthread_read, &args))
+ return -NET_ETHREAD;
return ret;
}
-/* write() ********************************************************************/
+/* TCP write() ****************************************************************/
-struct _pthread_write_args {
+struct gnet_pthread_write_args {
pthread_t cr_thread;
cid_t cr_coroutine;
@@ -206,13 +219,13 @@ struct _pthread_write_args {
ssize_t *ret;
};
-static void *_pthread_write(void *_args) {
- struct _pthread_read_args *args = _args;
+static void *gnet_pthread_write(void *_args) {
+ struct gnet_pthread_read_args *args = _args;
size_t done = 0;
while (done < args->count) {
ssize_t r = write(args->connfd, args->buf, args->count);
if (r < 0) {
- *(args->ret) = -errno;
+ gnet_map_errno(-errno);
break;
}
done += r;
@@ -223,12 +236,13 @@ static void *_pthread_write(void *_args) {
return NULL;
};
-static ssize_t gnet_write(implements_net_conn *_conn, void *buf, size_t count) {
- struct _gnet_conn *conn = VCALL_SELF(struct _gnet_conn, implements_net_conn, _conn);
+static ssize_t gnet_tcp_write(implements_net_stream_conn *_conn, void *buf, size_t count) {
+ struct _gnet_tcp_conn *conn =
+ VCALL_SELF(struct _gnet_tcp_conn, implements_net_stream_conn, _conn);
assert(conn);
ssize_t ret;
- struct _pthread_write_args args = {
+ struct gnet_pthread_write_args args = {
.cr_thread = pthread_self(),
.cr_coroutine = cr_getcid(),
@@ -238,15 +252,16 @@ static ssize_t gnet_write(implements_net_conn *_conn, void *buf, size_t count) {
.ret = &ret,
};
- if (RUN_PTHREAD(_pthread_write, &args))
- return -1;
+ if (RUN_PTHREAD(gnet_pthread_write, &args))
+ return -NET_ETHREAD;
return ret;
}
-/* close() ********************************************************************/
+/* TCP close() ****************************************************************/
-static int gnet_close(implements_net_conn *_conn, bool rd, bool wr) {
- struct _gnet_conn *conn = VCALL_SELF(struct _gnet_conn, implements_net_conn, _conn);
+static int gnet_tcp_close(implements_net_stream_conn *_conn, bool rd, bool wr) {
+ struct _gnet_tcp_conn *conn =
+ VCALL_SELF(struct _gnet_tcp_conn, implements_net_stream_conn, _conn);
assert(conn);
int how;
@@ -257,6 +272,180 @@ static int gnet_close(implements_net_conn *_conn, bool rd, bool wr) {
else if (!rd && wr)
how = SHUT_WR;
else
- return -EINVAL;
- return shutdown(conn->fd, how) ? -errno : 0;
+ assert(false);
+ return gnet_map_errno(shutdown(conn->fd, how) ? -errno : 0);
+}
+
+/* UDP init() *****************************************************************/
+
+static ssize_t gnet_udp_sendto(struct net_packet_conn *self, void *buf, size_t len,
+ struct net_ip4_addr addr, uint16_t port);
+static ssize_t gnet_udp_recvfrom(struct net_packet_conn *self, void *buf, size_t len,
+ struct net_ip4_addr *ret_addr, uint16_t *ret_port);
+static int gnet_udp_close(struct net_packet_conn *self);
+
+static struct net_packet_conn_vtable gnet_udp_conn_vtable = {
+ .sendto = gnet_udp_sendto,
+ .recvfrom = gnet_udp_recvfrom,
+ .close = gnet_udp_close,
+};
+
+void gnet_udp_conn_init(struct gnet_udp_conn *self, uint16_t port) {
+ int fd;
+ union {
+ struct sockaddr_in in;
+ struct sockaddr gen;
+ struct sockaddr_storage stor;
+ } addr = { 0 };
+
+ gnet_init();
+
+ addr.in.sin_family = AF_INET;
+ addr.in.sin_port = htons(port);
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0)
+ error(1, errno, "socket");
+ if (bind(fd, &addr.gen, sizeof addr) < 0)
+ error(1, errno, "bind");
+
+ self->vtable = &gnet_udp_conn_vtable;
+ self->fd = fd;
+}
+
+/* UDP sendto() ***************************************************************/
+
+struct gnet_pthread_sendto_args {
+ pthread_t cr_thread;
+ cid_t cr_coroutine;
+
+ int connfd;
+ void *buf;
+ size_t count;
+ struct net_ip4_addr node;
+ uint16_t port;
+
+ ssize_t *ret;
+};
+
+static void *gnet_pthread_sendto(void *_args) {
+ struct gnet_pthread_sendto_args *args = _args;
+ union {
+ struct sockaddr_in in;
+ struct sockaddr gen;
+ struct sockaddr_storage stor;
+ } addr = { 0 };
+
+ addr.in.sin_family = AF_INET;
+ addr.in.sin_addr.s_addr =
+ (((uint32_t)args->node.octets[0])<<24) |
+ (((uint32_t)args->node.octets[1])<<16) |
+ (((uint32_t)args->node.octets[2])<< 8) |
+ (((uint32_t)args->node.octets[3])<< 0) ;
+ addr.in.sin_port = htons(args->port);
+ *(args->ret) = sendto(args->connfd, args->buf, args->count, 0, &addr.gen, sizeof(addr));
+ if (*(args->ret) < 0)
+ *(args->ret) = gnet_map_errno(-errno);
+ WAKE_COROUTINE(args);
+ return NULL;
+}
+
+static ssize_t gnet_udp_sendto(struct net_packet_conn *_conn, void *buf, size_t count,
+ struct net_ip4_addr node, uint16_t port) {
+ struct gnet_udp_conn *conn =
+ VCALL_SELF(struct gnet_udp_conn, implements_net_packet_conn, _conn);
+ assert(conn);
+
+ ssize_t ret;
+ struct gnet_pthread_sendto_args args = {
+ .cr_thread = pthread_self(),
+ .cr_coroutine = cr_getcid(),
+
+ .connfd = conn->fd,
+ .buf = buf,
+ .count = count,
+ .node = node,
+ .port = port,
+
+ .ret = &ret,
+ };
+ if (RUN_PTHREAD(gnet_pthread_sendto, &args))
+ return -NET_ETHREAD;
+ return ret;
+}
+
+/* UDP recvfrom() *************************************************************/
+
+struct gnet_pthread_recvfrom_args {
+ pthread_t cr_thread;
+ cid_t cr_coroutine;
+
+ int connfd;
+ void *buf;
+ size_t count;
+
+ ssize_t *ret_size;
+ struct net_ip4_addr *ret_node;
+ uint16_t *ret_port;
+};
+
+static void *gnet_pthread_recvfrom(void *_args) {
+ struct gnet_pthread_recvfrom_args *args = _args;
+
+ union {
+ struct sockaddr_in in;
+ struct sockaddr gen;
+ struct sockaddr_storage stor;
+ } addr = { 0 };
+ socklen_t addr_size;
+
+ *(args->ret_size) = recvfrom(args->connfd, args->buf, args->count, 0, &addr.gen, &addr_size);
+ if (*(args->ret_size) < 0)
+ *(args->ret_size) = gnet_map_errno(-errno);
+ else {
+ assert(addr.in.sin_family == AF_INET);
+ if (args->ret_node) {
+ args->ret_node->octets[0] = (addr.in.sin_addr.s_addr >> 24) & 0xFF;
+ args->ret_node->octets[1] = (addr.in.sin_addr.s_addr >> 16) & 0xFF;
+ args->ret_node->octets[2] = (addr.in.sin_addr.s_addr >> 8) & 0xFF;
+ args->ret_node->octets[3] = (addr.in.sin_addr.s_addr >> 0) & 0xFF;
+ }
+ if (args->ret_port)
+ (*args->ret_port) = ntohs(addr.in.sin_port);
+ }
+ WAKE_COROUTINE(args);
+ return NULL;
+}
+
+static ssize_t gnet_udp_recvfrom(struct net_packet_conn *_conn, void *buf, size_t count,
+ struct net_ip4_addr *ret_node, uint16_t *ret_port) {
+ struct gnet_udp_conn *conn =
+ VCALL_SELF(struct gnet_udp_conn, implements_net_packet_conn, _conn);
+ assert(conn);
+
+ ssize_t ret;
+ struct gnet_pthread_recvfrom_args args = {
+ .cr_thread = pthread_self(),
+ .cr_coroutine = cr_getcid(),
+
+ .connfd = conn->fd,
+ .buf = buf,
+ .count = count,
+
+ .ret_size = &ret,
+ .ret_node = ret_node,
+ .ret_port = ret_port,
+ };
+ if (RUN_PTHREAD(gnet_pthread_recvfrom, &args))
+ return -NET_ETHREAD;
+ return ret;
+}
+
+/* UDP close() ****************************************************************/
+
+static int gnet_udp_close(struct net_packet_conn *_conn) {
+ struct gnet_udp_conn *conn =
+ VCALL_SELF(struct gnet_udp_conn, implements_net_packet_conn, _conn);
+ assert(conn);
+
+ return gnet_map_errno(close(conn->fd) ? -errno : 0);
}
diff --git a/cmd/srv9p/gnet.h b/cmd/srv9p/gnet.h
index 01f2d40..4380c1d 100644
--- a/cmd/srv9p/gnet.h
+++ b/cmd/srv9p/gnet.h
@@ -11,19 +11,27 @@
#include <libmisc/net.h>
-struct _gnet_conn {
- implements_net_conn;
+struct _gnet_tcp_conn {
+ implements_net_stream_conn;
int fd;
};
-struct gnet_listener {
- implements_net_listener;
+struct gnet_tcp_listener {
+ implements_net_stream_listener;
int fd;
- struct _gnet_conn active_conn;
+ struct _gnet_tcp_conn active_conn;
};
-void gnet_listener_init(struct gnet_listener *self, uint16_t port);
+void gnet_tcp_listener_init(struct gnet_tcp_listener *self, uint16_t port);
+
+struct gnet_udp_conn {
+ implements_net_packet_conn;
+
+ int fd;
+};
+
+void gnet_udp_conn_init(struct gnet_udp_conn *self, uint16_t port);
#endif /* _GNET_H_ */
diff --git a/cmd/srv9p/main.c b/cmd/srv9p/main.c
index d83fac4..7ed985f 100644
--- a/cmd/srv9p/main.c
+++ b/cmd/srv9p/main.c
@@ -91,8 +91,8 @@ static COROUTINE read_cr(void *_srv) {
cr_begin();
- struct gnet_listener listener;
- gnet_listener_init(&listener, 9000);
+ struct gnet_tcp_listener listener;
+ gnet_tcp_listener_init(&listener, 9000);
lib9p_srv_read_cr(srv, &listener);
diff --git a/lib9p/include/lib9p/srv.h b/lib9p/include/lib9p/srv.h
index 797695c..b9669d5 100644
--- a/lib9p/include/lib9p/srv.h
+++ b/lib9p/include/lib9p/srv.h
@@ -115,7 +115,7 @@ struct lib9p_srv {
* @errno LINUX_ERANGE R-message does not fit into max_msg_size
*/
-__attribute__ ((noreturn)) void lib9p_srv_read_cr(struct lib9p_srv *srv, implements_net_listener *listener);
+__attribute__ ((noreturn)) void lib9p_srv_read_cr(struct lib9p_srv *srv, implements_net_stream_listener *listener);
COROUTINE lib9p_srv_write_cr(void *_srv);
#endif /* _LIB9P_SRV_H_ */
diff --git a/lib9p/srv.c b/lib9p/srv.c
index cc4a048..8eef372 100644
--- a/lib9p/srv.c
+++ b/lib9p/srv.c
@@ -56,11 +56,11 @@ struct _srv_fidinfo {
struct _srv_conn {
/* immutable */
- struct lib9p_srv *parent_srv;
- implements_net_conn *fd;
- cid_t reader; /* the lib9p_srv_read_cr() coroutine */
+ struct lib9p_srv *parent_srv;
+ implements_net_stream_conn *fd;
+ cid_t reader; /* the lib9p_srv_read_cr() coroutine */
/* mutable */
- cr_mutex_t writelock;
+ cr_mutex_t writelock;
};
struct _srv_sess {
@@ -139,7 +139,7 @@ static void respond_error(struct _lib9p_srv_req *req) {
struct _srv_sess *sess = req->parent_sess;
/* Truncate the error-string if necessary to avoid needing to
- * return ERANGE. The assert() in
+ * return LINUX_ERANGE. The assert() in
* rerror_overhead_for_version() has checked that this
* addition doesn't overflow. */
if (((uint32_t)host.ename.len) + sess->rerror_overhead > sess->max_msg_size)
@@ -158,7 +158,7 @@ static void respond_error(struct _lib9p_srv_req *req) {
/* read coroutine *************************************************************/
-static bool read_at_least(implements_net_conn *fd, uint8_t *buf, size_t goal, size_t *done) {
+static bool read_at_least(implements_net_stream_conn *fd, uint8_t *buf, size_t goal, size_t *done) {
assert(buf);
assert(goal);
assert(done);
@@ -179,7 +179,7 @@ static bool read_at_least(implements_net_conn *fd, uint8_t *buf, size_t goal, si
static void handle_message(struct _lib9p_srv_req *ctx);
-__attribute__ ((noreturn)) void lib9p_srv_read_cr(struct lib9p_srv *srv, implements_net_listener *listener) {
+__attribute__ ((noreturn)) void lib9p_srv_read_cr(struct lib9p_srv *srv, implements_net_stream_listener *listener) {
uint8_t buf[CONFIG_9P_MAX_MSG_SIZE];
assert(srv);
diff --git a/libdhcp/dhcp.c b/libdhcp/dhcp.c
index 77f4b61..e638496 100644
--- a/libdhcp/dhcp.c
+++ b/libdhcp/dhcp.c
@@ -595,18 +595,11 @@ static int8_t dhcp_check_leasedIP(implements_net_udpsock *sock) {
uint8_t tmp;
int32_t ret;
- /* WIZchip RCR value changed for ARP Timeout count control */
- tmp = getRCR();
- setRCR(0x03);
-
/* IP conflict detection : ARP request - ARP reply */
/* Broadcasting ARP Request for check the IP conflict using UDP sendto() function */
ret = sendto(sock, "CHECK_IP_CONFLICT", 17, global_lease.addr, 5000);
- /* RCR value restore */
- setRCR(tmp);
-
- if(ret == SOCKERR_TIMEOUT) {
+ if (ret == SOCKERR_TIMEOUT) {
/* UDP send Timeout occurred : allocated IP address is unique, DHCP Success */
debugf("\r\n> Check leased IP - OK");
diff --git a/libmisc/include/libmisc/hash.h b/libmisc/include/libmisc/hash.h
new file mode 100644
index 0000000..5940e64
--- /dev/null
+++ b/libmisc/include/libmisc/hash.h
@@ -0,0 +1,31 @@
+/* libmisc/hash.h - General-purpose hash utilities
+ *
+ * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-Licence-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _LIBMISC_HASH_H_
+#define _LIBMISC_HASH_H_
+
+#include <stdint.h> /* for uint{n}_t */
+#include <stddef.h> /* for size_t */
+
+/* djb2 hash */
+typedef uint32_t hash_t;
+static inline void hash_init(hash_t *hash) {
+ *hash = 5381;
+}
+static inline void hash_write(hash_t *hash, void *dat, size_t len) {
+ for (size_t i = 0; i < len; i++)
+ *hash = (*hash * 33) + (hash_t)(((unsigned char *)dat)[i]);
+}
+
+/* utilities */
+static inline hash_t hash(void *dat, size_t len) {
+ hash_t h;
+ hash_init(&h);
+ hash_write(&h, dat, len);
+ return h;
+}
+
+#endif /* _LIBMISC_HASH_H_ */
diff --git a/libmisc/include/libmisc/net.h b/libmisc/include/libmisc/net.h
index e5648f5..43c4a48 100644
--- a/libmisc/include/libmisc/net.h
+++ b/libmisc/include/libmisc/net.h
@@ -9,8 +9,17 @@
#include <stdbool.h> /* for bool */
#include <stddef.h> /* for size_t */
+#include <stdint.h> /* for uint{n}_t} */
#include <sys/types.h> /* for ssize_t */
+/* Errnos *********************************************************************/
+
+#define NET_EOTHER 1
+#define NET_ETIMEDOUT 2
+#define NET_ETHREAD 3
+
+/* Address types **************************************************************/
+
struct net_ip4_addr {
unsigned char octets[4];
};
@@ -22,23 +31,25 @@ struct net_eth_addr {
unsigned char octets[6];
};
-struct net_conn;
-struct net_listener;
+/* Streams (e.g. TCP) *********************************************************/
-struct net_listener_vtable {
+struct net_stream_listener;
+struct net_stream_conn;
+
+struct net_stream_listener_vtable {
/**
* It is invalid to accept() a new connection if an existing
* connection is still open.
*/
- struct net_conn *(*accept)(struct net_listener *self);
+ struct net_stream_conn *(*accept)(struct net_stream_listener *self);
};
-struct net_conn_vtable {
+struct net_stream_conn_vtable {
/**
* Return bytes-read on success, 0 on EOF, -errno on error; a
* short read is *not* an error.
*/
- ssize_t (*read)(struct net_conn *self, void *buf, size_t count);
+ ssize_t (*read)(struct net_stream_conn *self, void *buf, size_t count);
/**
* Return `count` on success, -errno on error; a short write *is* an
@@ -48,20 +59,36 @@ struct net_conn_vtable {
* expensive to implement), so if you have concurrent writers then you
* should arrange for a mutex to protect the connection.
*/
- ssize_t (*write)(struct net_conn *self, void *buf, size_t count);
+ ssize_t (*write)(struct net_stream_conn *self, void *buf, size_t count);
/**
* Return 0 on success, -errno on error.
*/
- int (*close)(struct net_conn *self, bool rd, bool wr);
+ int (*close)(struct net_stream_conn *self, bool rd, bool wr);
};
-typedef struct net_listener {
- struct net_listener_vtable *vtable;
-} implements_net_listener;
+typedef struct net_stream_listener {
+ struct net_stream_listener_vtable *vtable;
+} implements_net_stream_listener;
+
+typedef struct net_stream_conn {
+ struct net_stream_conn_vtable *vtable;
+} implements_net_stream_conn;
+
+/* Packets (e.g. UDP) *********************************************************/
+
+struct net_packet_conn;
+
+struct net_packet_conn_vtable {
+ ssize_t (*sendto )(struct net_packet_conn *self, void *buf, size_t len,
+ struct net_ip4_addr node, uint16_t port);
+ ssize_t (*recvfrom)(struct net_packet_conn *self, void *buf, size_t len,
+ struct net_ip4_addr *ret_node, uint16_t *ret_port);
+ int (*close )(struct net_packet_conn *self);
+};
-typedef struct net_conn {
- struct net_conn_vtable *vtable;
-} implements_net_conn;
+typedef struct net_packet_conn {
+ struct net_packet_conn_vtable *vtable;
+} implements_net_packet_conn;
#endif /* _LIBMISC_NET_H_ */