summaryrefslogtreecommitdiff
path: root/kernel/sysnet.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/sysnet.c')
-rw-r--r--kernel/sysnet.c185
1 files changed, 185 insertions, 0 deletions
diff --git a/kernel/sysnet.c b/kernel/sysnet.c
new file mode 100644
index 0000000..1c48cb3
--- /dev/null
+++ b/kernel/sysnet.c
@@ -0,0 +1,185 @@
+//
+// network system calls.
+//
+
+#include "types.h"
+#include "param.h"
+#include "memlayout.h"
+#include "riscv.h"
+#include "spinlock.h"
+#include "proc.h"
+#include "defs.h"
+#include "fs.h"
+#include "sleeplock.h"
+#include "file.h"
+#include "net.h"
+
+struct sock {
+ struct sock *next; // the next socket in the list
+ uint32 raddr; // the remote IPv4 address
+ uint16 lport; // the local UDP port number
+ uint16 rport; // the remote UDP port number
+ struct spinlock lock; // protects the rxq
+ struct mbufq rxq; // a queue of packets waiting to be received
+};
+
+static struct spinlock lock;
+static struct sock *sockets;
+
+void
+sockinit(void)
+{
+ initlock(&lock, "socktbl");
+}
+
+int
+sockalloc(struct file **f, uint32 raddr, uint16 lport, uint16 rport)
+{
+ struct sock *si, *pos;
+
+ si = 0;
+ *f = 0;
+ if ((*f = filealloc()) == 0)
+ goto bad;
+ if ((si = (struct sock*)kalloc()) == 0)
+ goto bad;
+
+ // initialize objects
+ si->raddr = raddr;
+ si->lport = lport;
+ si->rport = rport;
+ initlock(&si->lock, "sock");
+ mbufq_init(&si->rxq);
+ (*f)->type = FD_SOCK;
+ (*f)->readable = 1;
+ (*f)->writable = 1;
+ (*f)->sock = si;
+
+ // add to list of sockets
+ acquire(&lock);
+ pos = sockets;
+ while (pos) {
+ if (pos->raddr == raddr &&
+ pos->lport == lport &&
+ pos->rport == rport) {
+ release(&lock);
+ goto bad;
+ }
+ pos = pos->next;
+ }
+ si->next = sockets;
+ sockets = si;
+ release(&lock);
+ return 0;
+
+bad:
+ if (si)
+ kfree((char*)si);
+ if (*f)
+ fileclose(*f);
+ return -1;
+}
+
+void
+sockclose(struct sock *si)
+{
+ struct sock **pos;
+ struct mbuf *m;
+
+ // remove from list of sockets
+ acquire(&lock);
+ pos = &sockets;
+ while (*pos) {
+ if (*pos == si){
+ *pos = si->next;
+ break;
+ }
+ pos = &(*pos)->next;
+ }
+ release(&lock);
+
+ // free any pending mbufs
+ while (!mbufq_empty(&si->rxq)) {
+ m = mbufq_pophead(&si->rxq);
+ mbuffree(m);
+ }
+
+ kfree((char*)si);
+}
+
+int
+sockread(struct sock *si, uint64 addr, int n)
+{
+ struct proc *pr = myproc();
+ struct mbuf *m;
+ int len;
+
+ acquire(&si->lock);
+ while (mbufq_empty(&si->rxq) && !pr->killed) {
+ sleep(&si->rxq, &si->lock);
+ }
+ if (pr->killed) {
+ release(&si->lock);
+ return -1;
+ }
+ m = mbufq_pophead(&si->rxq);
+ release(&si->lock);
+
+ len = m->len;
+ if (len > n)
+ len = n;
+ if (copyout(pr->pagetable, addr, m->head, len) == -1) {
+ mbuffree(m);
+ return -1;
+ }
+ mbuffree(m);
+ return len;
+}
+
+int
+sockwrite(struct sock *si, uint64 addr, int n)
+{
+ struct proc *pr = myproc();
+ struct mbuf *m;
+
+ m = mbufalloc(MBUF_DEFAULT_HEADROOM);
+ if (!m)
+ return -1;
+
+ if (copyin(pr->pagetable, mbufput(m, n), addr, n) == -1) {
+ mbuffree(m);
+ return -1;
+ }
+ net_tx_udp(m, si->raddr, si->lport, si->rport);
+ return n;
+}
+
+// called by protocol handler layer to deliver UDP packets
+void
+sockrecvudp(struct mbuf *m, uint32 raddr, uint16 lport, uint16 rport)
+{
+ //
+ // Find the socket that handles this mbuf and deliver it, waking
+ // any sleeping reader. Free the mbuf if there are no sockets
+ // registered to handle it.
+ //
+ struct sock *si;
+
+ acquire(&lock);
+ si = sockets;
+ while (si) {
+ if (si->raddr == raddr && si->lport == lport && si->rport == rport)
+ goto found;
+ si = si->next;
+ }
+ release(&lock);
+ mbuffree(m);
+ return;
+
+found:
+ acquire(&si->lock);
+ mbufq_pushtail(&si->rxq, m);
+ wakeup(&si->rxq);
+ release(&si->lock);
+ release(&lock);
+}