// // 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); }