186 lines
3.3 KiB
C
186 lines
3.3 KiB
C
//
|
|
// 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);
|
|
}
|