summaryrefslogtreecommitdiff
path: root/scalls
diff options
context:
space:
mode:
authorAnton Kling <anton@kling.gg>2023-10-27 19:41:26 +0200
committerAnton Kling <anton@kling.gg>2023-10-30 21:49:48 +0100
commit4f9ed7087cb58683d9423ab771ad76b31dac5514 (patch)
tree5364217b7d491c4321830025020ab13513067cb1 /scalls
parent715274d3a77c58510b97c3f87cd604dde9de7a4f (diff)
Kernel: Expose source information of incoming UDP packets
Diffstat (limited to 'scalls')
-rw-r--r--scalls/recvfrom.c52
-rw-r--r--scalls/recvfrom.h11
2 files changed, 57 insertions, 6 deletions
diff --git a/scalls/recvfrom.c b/scalls/recvfrom.c
index 0e37153..1770fa1 100644
--- a/scalls/recvfrom.c
+++ b/scalls/recvfrom.c
@@ -1,15 +1,59 @@
+#include <assert.h>
#include <fs/vfs.h>
+#include <math.h>
#include <poll.h>
#include <scalls/recvfrom.h>
-size_t syscall_recvfrom(int socket, void *buffer, size_t length, int flags,
- struct sockaddr *address, socklen_t *address_len) {
+size_t syscall_recvfrom(
+ int socket, void *buffer, size_t length, int flags,
+ struct two_args
+ *extra_args /*struct sockaddr *address, socklen_t *address_len*/) {
+
+ struct sockaddr *address = (struct sockaddr *)extra_args->a;
+ socklen_t *address_len = (socklen_t *)extra_args->b;
+ kprintf("address: %x\n", address);
+ kprintf("address_len: %x\n", address_len);
+
if (flags & MSG_WAITALL) {
struct pollfd fds[1];
fds[0].fd = socket;
fds[0].events = POLLIN;
poll(fds, 1, 0);
}
- kprintf("got event\n");
- return vfs_pread(socket, buffer, length, 0);
+
+ uint16_t data_length;
+ socklen_t tmp_socklen;
+ vfs_pread(socket, &tmp_socklen, sizeof(socklen_t), 0);
+ if (address_len)
+ *address_len = tmp_socklen;
+ if (address) {
+ vfs_pread(socket, address, tmp_socklen, 0);
+ } else {
+ // We still have to throwaway the data.
+ char devnull[100];
+ for (; tmp_socklen;) {
+ int rc = vfs_pread(socket, devnull, min(tmp_socklen, 100), 0);
+ assert(rc >= 0);
+ tmp_socklen -= rc;
+ }
+ }
+
+ vfs_pread(socket, &data_length, sizeof(data_length), 0);
+ // If it is reading less than the packet length that could cause
+ // problems as the next read will not be put at a new header. Luckily
+ // it seems as if other UNIX systems can discard the rest of the
+ // packet if not read.
+
+ // Read in the data requested
+ int read_len = min(length, data_length);
+ int rc = vfs_pread(socket, buffer, read_len, 0);
+ // Discard the rest of the packet
+ int rest = data_length - read_len;
+ char devnull[100];
+ for (; rest;) {
+ int rc = vfs_pread(socket, devnull, 100, 0);
+ assert(rc >= 0);
+ rest -= rc;
+ }
+ return rc;
}
diff --git a/scalls/recvfrom.h b/scalls/recvfrom.h
index 9897899..d81a1e0 100644
--- a/scalls/recvfrom.h
+++ b/scalls/recvfrom.h
@@ -1,4 +1,11 @@
#include <socket.h>
-size_t syscall_recvfrom(int socket, void *buffer, size_t length, int flags,
- struct sockaddr *address, socklen_t *address_len);
+struct two_args {
+ uint32_t a;
+ uint32_t b;
+};
+
+size_t syscall_recvfrom(
+ int socket, void *buffer, size_t length, int flags,
+ struct two_args
+ *extra_args /*struct sockaddr *address, socklen_t *address_len*/);