summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/sbc_harness/config/config.h1
-rw-r--r--lib9p/9p.c5
-rwxr-xr-xlib9p/9p.gen14
-rw-r--r--lib9p/9p.generated.c10
-rw-r--r--lib9p/CMakeLists.txt2
-rw-r--r--lib9p/include/lib9p/9p.generated.h4
-rw-r--r--lib9p/include/lib9p/9p.h1
-rw-r--r--lib9p/include/lib9p/srv.h72
-rw-r--r--lib9p/internal.h2
-rw-r--r--lib9p/map.h102
-rw-r--r--lib9p/srv.c76
11 files changed, 271 insertions, 18 deletions
diff --git a/cmd/sbc_harness/config/config.h b/cmd/sbc_harness/config/config.h
index 5a3d5a1..c3c65bf 100644
--- a/cmd/sbc_harness/config/config.h
+++ b/cmd/sbc_harness/config/config.h
@@ -55,6 +55,7 @@
* struct padding, (2) nul-terminator byes for strings.
*/
# define CONFIG_9P_MAX_HOSTMSG_SIZE CONFIG_9P_MAX_MSG_SIZE+16
+# define CONFIG_9P_MAX_FIDS 16
#endif
#endif /* _CONFIG_H */
diff --git a/lib9p/9p.c b/lib9p/9p.c
index af1c6ca..fffef31 100644
--- a/lib9p/9p.c
+++ b/lib9p/9p.c
@@ -23,6 +23,11 @@ uint32_t lib9p_ctx_max_msg_size(struct lib9p_ctx *ctx) {
return ctx->max_msg_size;
}
+bool lib9p_ctx_has_error(struct lib9p_ctx *ctx) {
+ assert(ctx);
+ return ctx->err_num || ctx->err_msg[0];
+}
+
int lib9p_error(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *msg) {
strncpy(ctx->err_msg, msg, sizeof(ctx->err_msg));
ctx->err_msg[sizeof(ctx->err_msg)-1] = '\0';
diff --git a/lib9p/9p.gen b/lib9p/9p.gen
index 6f2ad2c..cdec067 100755
--- a/lib9p/9p.gen
+++ b/lib9p/9p.gen
@@ -433,7 +433,10 @@ enum {idprefix}version {{
for member in struct.members:
if struct.name == "stat" and member.name == "stat_size": # SPECIAL
continue
- ret += f"\t{c_typename(idprefix, member.typ).ljust(typewidth)} {'*' if member.cnt else ' '}{member.name};"
+ ctype = c_typename(idprefix, member.typ)
+ if (struct.name in ["d", "s"]) and member.cnt: # SPECIAL
+ ctype = "char"
+ ret += f"\t{ctype.ljust(typewidth)} {'*' if member.cnt else ' '}{member.name};"
if (not all_the_same) and (comment := c_vercomment(member.ver)):
ret += (" " * (namewidth - len(member.name))) + " " + comment
ret += "\n"
@@ -689,8 +692,8 @@ static ALWAYS_INLINE bool _validate_list(struct _validate_ctx *ctx,
prev_size = member.static_size
if typ.name == "stat": # SPECIAL
assert typ.members[0].static_size
- ret += f"\n{prefix1}((uint32_t)decode_u{typ.members[0].static_size*8}le(&ctx->net_bytes[size_offset]) != ctx->net_offset - size_offset)"
- ret += f'\n{prefix2}\t? lib9p_error(ctx->ctx, LINUX_EBADMSG, "stat size does not match stat contents")"'
+ ret += f"\n{prefix1}((uint32_t)decode_u{typ.members[0].static_size*8}le(&ctx->net_bytes[size_offset]) != ctx->net_offset - size_offset"
+ ret += f'\n{prefix2}\t? lib9p_error(ctx->ctx, LINUX_EBADMSG, "stat size does not match stat contents")'
ret += f"\n{prefix2}\t: false)"
ret += ";\n"
ret += "}\n"
@@ -738,7 +741,7 @@ static ALWAYS_INLINE void unmarshal_8(struct _unmarshal_ctx *ctx, uint64_t *out)
struct_versions = typ.members[0].ver
for member in typ.members:
if typ.name == "stat" and member.name == "stat_size": # SPECIAL
- ret += f"\tsize->net_offset += {member.static_size};\n"
+ ret += f"\tctx->net_offset += {member.static_size};\n"
continue
ret += "\t"
prefix = "\t"
@@ -835,9 +838,10 @@ static ALWAYS_INLINE bool marshal_8(struct _marshal_ctx *ctx, uint64_t *val) {
for member in typ.members:
if typ.name == "stat" and member.name == "stat_size": # SPECIAL:
assert member.static_size
- ret += f"\n{prefix }((ctx->net_offset + {member.static_size} > ctx->ctx->max_msg_size)"
+ ret += f"\n{prefix }(ctx->net_offset + {member.static_size} > ctx->ctx->max_msg_size"
ret += f"\n{prefix2}\t? _marshal_too_large(ctx)"
ret += f"\n{prefix2}\t: ({{ ctx->net_offset += {member.static_size}; false; }}))"
+ prefix = prefix1
continue
ret += f"\n{prefix}"
if member.ver != struct_versions:
diff --git a/lib9p/9p.generated.c b/lib9p/9p.generated.c
index 4ec5ae5..fc243f5 100644
--- a/lib9p/9p.generated.c
+++ b/lib9p/9p.generated.c
@@ -400,8 +400,8 @@ static ALWAYS_INLINE bool validate_stat(struct _validate_ctx *ctx) {
|| ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && validate_4(ctx) )
|| ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && validate_4(ctx) )
|| ( (ctx->ctx->version==LIB9P_VER_9P2000_u) && validate_4(ctx) )
- || ((uint32_t)decode_u16le(&ctx->net_bytes[size_offset]) != ctx->net_offset - size_offset)
- ? lib9p_error(ctx->ctx, LINUX_EBADMSG, "stat size does not match stat contents")"
+ || ((uint32_t)decode_u16le(&ctx->net_bytes[size_offset]) != ctx->net_offset - size_offset
+ ? lib9p_error(ctx->ctx, LINUX_EBADMSG, "stat size does not match stat contents")
: false);
}
@@ -642,7 +642,7 @@ static ALWAYS_INLINE void unmarshal_qid(struct _unmarshal_ctx *ctx, struct lib9p
static ALWAYS_INLINE void unmarshal_stat(struct _unmarshal_ctx *ctx, struct lib9p_stat *out) {
memset(out, 0, sizeof(*out));
- size->net_offset += 2;
+ ctx->net_offset += 2;
unmarshal_2(ctx, &out->kern_type);
unmarshal_4(ctx, &out->kern_dev);
unmarshal_qid(ctx, &out->file_qid);
@@ -943,10 +943,10 @@ static ALWAYS_INLINE bool marshal_qid(struct _marshal_ctx *ctx, struct lib9p_qid
static ALWAYS_INLINE bool marshal_stat(struct _marshal_ctx *ctx, struct lib9p_stat *val) {
uint32_t size_offset = ctx->net_offset;
- return ((ctx->net_offset + 2 > ctx->ctx->max_msg_size)
+ return (ctx->net_offset + 2 > ctx->ctx->max_msg_size
? _marshal_too_large(ctx)
: ({ ctx->net_offset += 2; false; }))
- return marshal_2(ctx, &val->kern_type)
+ || marshal_2(ctx, &val->kern_type)
|| marshal_4(ctx, &val->kern_dev)
|| marshal_qid(ctx, &val->file_qid)
|| marshal_dm(ctx, &val->file_mode)
diff --git a/lib9p/CMakeLists.txt b/lib9p/CMakeLists.txt
index 811e81a..3584d7a 100644
--- a/lib9p/CMakeLists.txt
+++ b/lib9p/CMakeLists.txt
@@ -6,7 +6,7 @@
add_library(lib9p INTERFACE)
target_include_directories(lib9p SYSTEM INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_sources(lib9p INTERFACE
- types.c
+ 9p.generated.c
9p.c
srv.c
)
diff --git a/lib9p/include/lib9p/9p.generated.h b/lib9p/include/lib9p/9p.generated.h
index f093aa1..135cf8a 100644
--- a/lib9p/include/lib9p/9p.generated.h
+++ b/lib9p/include/lib9p/9p.generated.h
@@ -81,12 +81,12 @@ typedef uint8_t lib9p_o_t;
struct lib9p_d {
uint32_t len;
- uint8_t *dat;
+ char *dat;
};
struct lib9p_s {
uint16_t len;
- uint8_t *utf8;
+ char *utf8;
};
struct lib9p_qid {
diff --git a/lib9p/include/lib9p/9p.h b/lib9p/include/lib9p/9p.h
index 8e57a86..b96c938 100644
--- a/lib9p/include/lib9p/9p.h
+++ b/lib9p/include/lib9p/9p.h
@@ -19,6 +19,7 @@
struct lib9p_ctx;
enum lib9p_version lib9p_ctx_version(struct lib9p_ctx *);
uint32_t lib9p_ctx_max_msg_size(struct lib9p_ctx *);
+bool lib9p_ctx_has_error(struct lib9p_ctx *);
/** Write an static error into ctx, return -1. */
int lib9p_error(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *msg);
diff --git a/lib9p/include/lib9p/srv.h b/lib9p/include/lib9p/srv.h
index 9220bd9..11894ea 100644
--- a/lib9p/include/lib9p/srv.h
+++ b/lib9p/include/lib9p/srv.h
@@ -4,11 +4,77 @@
#include <libcr/coroutine.h>
#include <libcr_ipc/chan.h>
-struct lib9p_req;
+#include <lib9p/9p.h>
+
+/* vtables you must implement *************************************************/
+
+struct lib9p_srv_file_vtable {
+ /* all */
+ struct lib9p_srv_io (*io )(struct lib9p_srv_reqctx *ctx, void *impldata,
+ lib9p_o_t flags);
+ struct lib9p_stat (*stat )(struct lib9p_srv_reqcggtx *ctx, void *impldata);
+ void (*wstat )(struct lib9p_srv_reqctx *ctx, void *impldata,
+ struct lib9p_stat new);
+ void (*remove )(struct lib9p_srv_reqctx *ctx, void *impldata);
+ void (*free )(struct lib9p_srv_reqctx *ctx, void *impldata);
+
+ /* dir */
+ struct lib9p_srv_file (*openchild )(struct lib9p_srv_reqctx *ctx, void *impldata,
+ char *childname);
+ struct lib9p_srv_file (*createchild)(struct lib9p_srv_reqctx *ctx, void *impldata,
+ char *childname, lib9p_dm_t perm, lib9p_o_t flags);
+};
+
+struct lib9p_srv_io_dir_vtable {
+ size_t (*readdir )(struct lib9p_srv_reqctx *ctx, void *impldata,
+ struct lib9p_stat *buf, size_t count, size_t offset);
+};
+
+struct lib9p_srv_io_file_vtable {
+ uint32_t (*pread )(struct lib9p_srv_reqctx *ctx, void *impldata,
+ void *buf, uint32_t count, uint64_t offset);
+ uint32_t (*pwrite )(struct lib9p_srv_reqctx *ctx, void *impldata,
+ void *buf, uint32_t count, uint64_t offset);
+};
+
+/* objects you'll deal with ***************************************************/
+
+struct lib9p_srv_reqctx {
+ struct lib9p_ctx ctx;
+ uint32_t uid;
+ char *uname;
+};
+
+struct lib9p_srv_file {
+ struct lib9p_srv_file_vtable vtable;
+
+ struct lib9p_srv_file *parent_dir;
+ void *impldata;
+};
+
+struct lib9p_srv_io {
+ union {
+ struct lib9p_srv_io_dir_vtable dir;
+ struct lib9p_srv_io_file_vtable file;
+ } vtable;
+
+ struct lib9p_srv_file *file;
+ struct lib9p_qid qid;
+ uint32_t iounit;
+
+ void *impldata;
+};
+
+/******************************************************************************/
struct lib9p_srv {
- int sockfd;
- cr_chan_t(struct lib9p_req *) reqch;
+ /* Things you provide */
+ int sockfd;
+ void /*TODO*/ (*auth)(struct lib9p_srv_reqctx *ctx, char *treename);
+ struct lib9p_srv_file (*rootdir)(struct lib9p_srv_reqctx *ctx, char *treename);
+
+ /* For internal use */
+ cr_chan_t(struct lib9p_req *) reqch;
};
/**
diff --git a/lib9p/internal.h b/lib9p/internal.h
index 40cfcee..cbec829 100644
--- a/lib9p/internal.h
+++ b/lib9p/internal.h
@@ -27,6 +27,8 @@ static_assert(CONFIG_9P_MAX_ERR_SIZE + CONFIG_9P_MAX_MSG_SIZE + 2*CONFIG_9P_MAX_
#define ALWAYS_INLINE inline __attribute__((always_inline))
#define FLATTEN __attribute__((flatten))
#define ARRAY_LEN(arr) (sizeof(arr)/sizeof((arr)[0]))
+#define CAT2(a, b) a##b
+#define CAT3(a, b, c) a##b##c
/* types **********************************************************************/
diff --git a/lib9p/map.h b/lib9p/map.h
new file mode 100644
index 0000000..a8d26b5
--- /dev/null
+++ b/lib9p/map.h
@@ -0,0 +1,102 @@
+/* lib9p/map.h - A really dumb map/dict data structur
+ *
+ * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-Licence-Identifier: AGPL-3.0-or-later
+ */
+
+#include "internal.h"
+
+/**
+ * `#define` `NAME`, `KEY_T`, `VAL_T`, and `CAP`; then `#include
+ * "map.h".
+ */
+
+#ifndef NAME
+# error NAME must be defined
+#endif
+#ifndef KEY_T
+# error KEY_T must be defined
+#endif
+#ifndef VAL_T
+# error VAL_T must be defined
+#endif
+#ifndef CAP
+# error CAP must be defined
+#endif
+
+#ifndef MAP_KEY
+#define MAP_KV(TNAME) CAT3(_,TNAME,_kv)
+#define MAP_METHOD(TNAME, MNAME) CAT3(TNAME,_,MNAME)
+#endif
+
+/* This implementation is just an array that we brute-force search
+ * over for a slot. I don't want to use the heap, which means
+ * statically-sized maps, and I'm probably going to choose a low
+ * static size, so this is fine. */
+
+struct MAP_KV(NAME) {
+ bool set;
+ KEY_T key;
+ VAL_T val;
+};
+
+struct NAME {
+ size_t len;
+ struct MAP_KV(NAME) items[CAP];
+};
+
+/**
+ * Load an item from the map; return a pointer to the in-map value, or
+ * NULL if the item is not in the map.
+ */
+static VAL_T *MAP_METHOD(NAME,load)(struct NAME *m, KEY_T k) {
+ if (!m->len)
+ return NULL;
+ for (size_t i = 0; i < ARRAY_LEN(m->items); i++)
+ if (m->items[i].set && m->items[i].key == k)
+ return &(m->items[i].val);
+ return NULL;
+}
+
+/**
+ * Store an item into the map, perhaps replacing an existing value.
+ * Return a pointer to the in-map value, or NULL if the map is full.
+ */
+static VAL_T *MAP_METHOD(NAME,store)(struct NAME *m, KEY_T k, VAL_T v) {
+ VAL_T *old = MAP_METHOD(NAME,load)(m, k);
+ if (old) {
+ *old = v;
+ return old;
+ }
+ if (m->len == ARRAY_LEN(m->items))
+ return NULL;
+ for (size_t i = 0; i < ARRAY_LEN(m->items); i++)
+ if (!m->items[i].set) {
+ m->items[i].set = true;
+ m->items[i].key = k;
+ m->items[i].val = v;
+ return &(m->items[i].val);
+ }
+ assert(false);
+}
+
+/**
+ * Delete an item from the map. Returns true if an item was deleted,
+ * false if no such item was in the map.
+ */
+static bool MAP_METHOD(NAME,del)(struct NAME *m, KEY_T k) {
+ if (!m->len)
+ return NULL;
+ for (size_t i = 0; i < ARRAY_LEN(m->items); i++)
+ if (m->items[i].set && m->items[i].key == k) {
+ m->items[i].set = false;
+ m->len--;
+ return true;
+ }
+ return false;
+}
+
+#undef NAME
+#undef KEY_T
+#undef VAL_T
+#undef CAP
diff --git a/lib9p/srv.c b/lib9p/srv.c
index f25fe09..1510a4a 100644
--- a/lib9p/srv.c
+++ b/lib9p/srv.c
@@ -14,6 +14,12 @@
/* structs ********************************************************************/
+#define NAME fidmap
+#define KEY_T uint32_t
+#define VAL_T struct lib9p_srv_file
+#define CAP CONFIG_9P_MAX_FIDS
+#include "map.h"
+
/* The hierarchy of concepts is:
*
* server -> connection -> session -> request
@@ -40,6 +46,7 @@ struct lib9p_sess {
/* mutable */
bool initialized;
unsigned int refcount;
+ struct fidmap fids;
};
struct lib9p_req {
@@ -48,7 +55,7 @@ struct lib9p_req {
uint16_t tag;
/* mutable */
uint8_t *net_bytes; /* CONFIG_9P_MAX_MSG_SIZE-sized */
- struct lib9p_ctx ctx;
+ struct lib9p_reqctx ctx;
};
/* base utilities *************************************************************/
@@ -195,6 +202,8 @@ COROUTINE lib9p_srv_read_cr(void *_srv) {
/* write coroutine ************************************************************/
static void handle_Tversion(struct lib9p_req *ctx, struct lib9p_msg_Tversion *req, struct lib9p_msg_Rversion *resp);
+static void handle_Tauth(struct lib9p_req *ctx, struct lib9p_msg_Tauth *req, struct lib9p_msg_Rauth *resp);
+static void handle_Tattach(struct lib9p_req *ctx, struct lib9p_msg_Tattach *req, struct lib9p_msg_Rattach *resp);
COROUTINE lib9p_srv_write_cr(void *_srv) {
uint8_t net[CONFIG_9P_MAX_MSG_SIZE];
@@ -287,7 +296,7 @@ COROUTINE lib9p_srv_write_cr(void *_srv) {
}
write:
- if (req.ctx.err_num || req.ctx.err_msg[0])
+ if (lib9p_ctx_has_error(&req.ctx))
respond_error(&req);
else {
if (lib9p_marshal(&req.ctx, typ+1, req.tag, host_resp, net))
@@ -335,3 +344,66 @@ static void handle_Tversion(struct lib9p_req *ctx, struct lib9p_msg_Tversion *re
? CONFIG_9P_MAX_MSG_SIZE
: req->max_msg_size;
}
+
+static void handle_Tauth(struct lib9p_req *ctx, struct lib9p_msg_Tauth *UNUSED(req), struct lib9p_msg_Rauth *UNUSED(resp)) {
+ if (!ctx->parent_sess->parent_conn->parent_srv->auth) {
+ lib9p_error(&ctx->ctx, LINUX_EOPNOTSUPP, "authentication not required");
+ return;
+ }
+ ctx->ctx.uid = req->uid;
+ ctx->ctx.uname = req->uname.utf8;
+ lib9p_error(&ctx->ctx, LINUX_EOPNOTSUPP, "TODO: auth not implemented");
+ return;
+}
+
+static void handle_Tattach(struct lib9p_req *ctx, struct lib9p_msg_Tattach *req, struct lib9p_msg_Rattach *resp) {
+ ctx->ctx.uid = req->uid;
+ ctx->ctx.uname = req->uname.utf8;
+ if (ctx->parent_sess->parent_conn->parent_srv->auth) {
+ /*
+ struct lib9p_srv_filehandle *fh = fidmap_get(req->afid);
+ if (!fh)
+ lib9p_error(&ctx->ctx, LINUX_EACCES, "FID provided as auth-file is not a valid FID");
+ else if (fh->type != FH_AUTH)
+ lib9p_error(&ctx->ctx, LINUX_EACCES, "FID provided as auth-file is not an auth-file");
+ else if (strcmp(fh->data.auth.uname, req->uname.utf8) != 0)
+ lib9p_errorf(&ctx->ctx, LINUX_EACCES, "FID provided as auth-file is for user=\"%s\" and cannot be used for user=\"%s\"",
+ fh->data.auth.uname, req->uname.utf8);
+ else if (strcmp(fh->data.auth.aname, req->aname.utf8) != 0)
+ lib9p_errorf(&ctx->ctx, LINUX_EACCES, "FID provided as auth-file is for tree=\"%s\" and cannot be used for tree=\"%s\"",
+ fh->data.auth.aname, req->aname.utf8);
+ else if (!fh->data.auth.authenticated)
+ lib9p_error(&ctx->ctx, LINUX_EACCES, "FID provided as auth-file has not completed authentication");
+ fh->refcount--;
+ if (lib9p_ctx_has_error(&ctx->ctx))
+ return;
+ */
+ lib9p_error(&ctx->ctx, LINUX_EOPNOTSUPP, "TODO: auth not implemented");
+ return;
+ } else {
+ if (req->afid != LIB9P_NOFID) {
+ lib9p_error(&ctx->ctx, LINUX_EACCES, "FID provided as auth-file, but no auth-file is required");
+ return;
+ }
+ }
+
+ if (fidmap_load(&ctx->parent_sess->fids, req->fid)) {
+ lib9p_error(&ctx->ctx, LINUX_EBADF, "FID already in use");
+ return;
+ }
+
+ struct lib9p_srv_file rootdir = ctx->parent_sess->parent_conn->parent_srv->rootdir(&ctx->ctx, req->aname.utf8);
+ if (lib9p_ctx_has_error(&ctx->ctx.ctx))
+ return;
+
+ struct lib9p_srv_file *rootdir_ptr = fidmap_store(&ctx->parent_sess->fids, req->fid, rootdir);
+ if (!rootdir_ptr) {
+ lib9p_error(&ctx->ctx, LINUX_EMFILE, "too many open files");
+ if (rootdir.free)
+ rootdir.free(ctx, rootdir.impldata);
+ return;
+ }
+
+ resp->qid = rootdir.qid;
+ return;
+}