summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--network/ipv4.c6
-rw-r--r--network/udp.c47
-rw-r--r--network/udp.h2
-rw-r--r--scalls/recvfrom.c52
-rw-r--r--scalls/recvfrom.h11
-rw-r--r--userland/libc/include/socket.h1
6 files changed, 99 insertions, 20 deletions
diff --git a/network/ipv4.c b/network/ipv4.c
index 27b38ec..e7ef2c2 100644
--- a/network/ipv4.c
+++ b/network/ipv4.c
@@ -2,6 +2,7 @@
#include <network/bytes.h>
#include <network/ipv4.h>
#include <network/udp.h>
+#include <string.h>
void handle_ipv4(const uint8_t *payload, uint32_t packet_length) {
assert(packet_length > 4);
@@ -15,10 +16,13 @@ void handle_ipv4(const uint8_t *payload, uint32_t packet_length) {
// Make sure the ipv4 header is not trying to get uninitalized memory
assert(ipv4_total_length <= packet_length);
+ uint8_t src_ip[4];
+ memcpy(src_ip, payload + 12, sizeof(uint8_t[4]));
+
uint8_t protocol = *(payload + 9);
switch (protocol) {
case 0x11:
- handle_udp(payload + 20, ipv4_total_length - 20);
+ handle_udp(src_ip, payload + 20, ipv4_total_length - 20);
break;
default:
kprintf("Protocol given in IPv4 header not handeld: %x\n", protocol);
diff --git a/network/udp.c b/network/udp.c
index fb8ba44..29f17e1 100644
--- a/network/udp.c
+++ b/network/udp.c
@@ -3,24 +3,47 @@
#include <network/udp.h>
#include <socket.h>
-void handle_udp(const uint8_t *payload, uint32_t packet_length) {
+void handle_udp(uint8_t src_ip[4], const uint8_t *payload,
+ uint32_t packet_length) {
assert(packet_length >= 8);
- uint16_t source_port = ntohs(*(uint16_t *)payload);
- uint16_t dst_port = ntohs(*(uint16_t *)(payload + 2));
- uint16_t length = ntohs(*(uint16_t *)(payload + 4));
- assert(length == packet_length);
- kprintf("source_port: %d\n", source_port);
- kprintf("dst_port: %d\n", dst_port);
- uint32_t data_length = length - 8;
+ // n_.* means network format(big endian)
+ // h_.* means host format((probably) little endian)
+ uint16_t n_source_port = *(uint16_t *)payload;
+ uint16_t h_source_port = ntohs(n_source_port);
+ uint16_t h_dst_port = ntohs(*(uint16_t *)(payload + 2));
+ uint16_t h_length = ntohs(*(uint16_t *)(payload + 4));
+ assert(h_length == packet_length);
+ kprintf("source_port: %d\n", h_source_port);
+ kprintf("dst_port: %d\n", h_dst_port);
+ uint16_t data_length = h_length - 8;
const uint8_t *data = payload + 8;
// Find the open port
- OPEN_INET_SOCKET *in_s = find_open_udp_port(htons(dst_port));
+ OPEN_INET_SOCKET *in_s = find_open_udp_port(htons(h_dst_port));
assert(in_s);
SOCKET *s = in_s->s;
vfs_fd_t *fifo_file = s->ptr_socket_fd;
+
+ // Write the sockaddr struct such that it can later be
+ // given to userland if asked.
+ struct sockaddr_in /*{
+ sa_family_t sin_family;
+ union {
+ uint32_t s_addr;
+ } sin_addr;
+ uint16_t sin_port;
+ }*/ in;
+ in.sin_family = AF_INET;
+ memcpy(&in.sin_addr.s_addr, src_ip, sizeof(uint32_t));
+ in.sin_port = n_source_port;
+ socklen_t sock_length = sizeof(struct sockaddr_in);
+
+ raw_vfs_pwrite(fifo_file, &sock_length, sizeof(sock_length), 0);
+ raw_vfs_pwrite(fifo_file, &in, sizeof(in), 0);
+
+ // Write the UDP payload length(not including header)
+ raw_vfs_pwrite(fifo_file, &data_length, sizeof(uint16_t), 0);
+
+ // Write the UDP payload
raw_vfs_pwrite(fifo_file, (char *)data, data_length, 0);
- for (uint32_t i = 0; i < data_length; i++) {
- kprintf("%c", data[i]);
- }
}
diff --git a/network/udp.h b/network/udp.h
index c6ac753..8278b87 100644
--- a/network/udp.h
+++ b/network/udp.h
@@ -1,3 +1,3 @@
#include <stdint.h>
-void handle_udp(const uint8_t *payload, uint32_t packet_length);
+void handle_udp(uint8_t src_ip[4], const uint8_t *payload, uint32_t packet_length);
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*/);
diff --git a/userland/libc/include/socket.h b/userland/libc/include/socket.h
index c4a3e73..2bf6345 100644
--- a/userland/libc/include/socket.h
+++ b/userland/libc/include/socket.h
@@ -40,6 +40,7 @@ struct sockaddr_in {
sa_family_t sin_family;
union {
uint32_t s_addr;
+ uint8_t a[4];
} sin_addr;
uint16_t sin_port;
};