diff --git a/include/net/packet.h b/include/net/packet.h index de8fa4b..dd8e2b8 100644 --- a/include/net/packet.h +++ b/include/net/packet.h @@ -1,5 +1,6 @@ #pragma once #include "sys/types.h" +#include "sys/spin.h" struct netdev; // Takes up a single page @@ -17,6 +18,7 @@ struct packet_qh { }; struct packet_queue { + spin_t lock; struct packet_qh *head, *tail; }; diff --git a/net/net.c b/net/net.c index 923e380..cb453a7 100644 --- a/net/net.c +++ b/net/net.c @@ -20,7 +20,6 @@ #include "net/if.h" static struct thread netd_thread = {0}; -static spin_t g_rxq_lock = 0; static struct packet_queue g_rxq; static struct packet *packet_create(void); @@ -48,11 +47,8 @@ static void net_daemon(void) { continue; } - spin_lock_irqsave(&g_rxq_lock, &irq); p = packet_queue_pop(&g_rxq); _assert(p); - spin_release_irqrestore(&g_rxq_lock, &irq); - net_handle_packet(p); packet_unref(p); @@ -68,30 +64,37 @@ static inline struct packet_qh *packet_qh_create(struct packet *p) { void packet_queue_push(struct packet_queue *pq, struct packet *p) { struct packet_qh *qh = packet_qh_create(p); + qh->next = NULL; + uintptr_t irq; + spin_lock_irqsave(&pq->lock, &irq); if (pq->tail) { pq->tail->next = qh; } else { pq->head = qh; } qh->prev = pq->tail; - qh->next = NULL; pq->tail = qh; + spin_release_irqrestore(&pq->lock, &irq); } struct packet *packet_queue_pop(struct packet_queue *pq) { + uintptr_t irq; + spin_lock_irqsave(&pq->lock, &irq); struct packet_qh *qh = pq->head; _assert(qh); pq->head = qh->next; if (!pq->head) { pq->tail = NULL; } + spin_release_irqrestore(&pq->lock, &irq); struct packet *p = qh->packet; kfree(qh); return p; } void packet_queue_init(struct packet_queue *pq) { + pq->lock = 0; pq->head = NULL; pq->tail = NULL; } @@ -101,6 +104,7 @@ static struct packet *packet_create(void) { uintptr_t page = amd64_phys_alloc_page(); _assert(page != MM_NADDR); packet = (struct packet *) MM_VIRTUALIZE(page); + packet->refcount = 0; return packet; } @@ -135,9 +139,7 @@ int net_receive(struct netdev *dev, const void *data, size_t len) { p->dev = dev; packet_ref(p); - spin_lock(&g_rxq_lock); packet_queue_push(&g_rxq, p); - spin_release(&g_rxq_lock); return 0; } @@ -181,16 +183,24 @@ void net_close(struct vfs_ioctx *ioctx, struct ofile *fd) { _assert(fd); _assert(fd->flags & OF_SOCKET); - if (fd->socket.domain != AF_INET) { - kwarn("Unknown socket family: %d\n", fd->socket.domain); - return; - } - - switch (fd->socket.type) { - case SOCK_DGRAM: - udp_socket_close(ioctx, fd); + switch (fd->socket.domain) { + case AF_INET: + switch (fd->socket.type) { + case SOCK_DGRAM: + udp_socket_close(ioctx, fd); + break; + default: + break; + } break; - default: + case AF_PACKET: + switch (fd->socket.type) { + case SOCK_RAW: + raw_socket_close(ioctx, fd); + break; + default: + break; + } break; } } diff --git a/net/raw.c b/net/raw.c index 9d7c41c..780e8c9 100644 --- a/net/raw.c +++ b/net/raw.c @@ -16,6 +16,7 @@ struct raw_socket { struct raw_socket *prev, *next; }; +static spin_t g_raw_lock = 0; static struct raw_socket *g_raw_sockets = NULL; int raw_socket_open(struct vfs_ioctx *ioctx, struct ofile *fd, int dom, int type, int proto) { @@ -69,9 +70,23 @@ ssize_t raw_socket_recv(struct vfs_ioctx *ioctx, struct ofile *fd, void *buf, si } void raw_socket_close(struct vfs_ioctx *ioctx, struct ofile *fd) { - struct raw_socket *r_sock = kmalloc(sizeof(struct raw_socket)); + uintptr_t irq; + struct raw_socket *r_sock = fd->socket.sock; _assert(r_sock); + spin_lock_irqsave(&g_raw_lock, &irq); + struct raw_socket *prev = r_sock->prev; + struct raw_socket *next = r_sock->next; + if (prev) { + prev->next = next; + } else { + g_raw_sockets = next; + } + if (next) { + next->prev = prev; + } + spin_release_irqrestore(&g_raw_lock, &irq); + // Flush packet queue while (r_sock->queue.head) { struct packet *p = packet_queue_pop(&r_sock->queue); @@ -81,11 +96,17 @@ void raw_socket_close(struct vfs_ioctx *ioctx, struct ofile *fd) { void raw_packet_handle(struct packet *p) { // Queue the packet for all the sockets + uintptr_t irq; + // TODO: too much time spent in spinlocked region? + spin_lock_irqsave(&g_raw_lock, &irq); for (struct raw_socket *r = g_raw_sockets; r; r = r->next) { packet_ref(p); packet_queue_push(&r->queue, p); - if (r->wait) { - sched_queue(r->wait); + struct thread *w = r->wait; + if (w) { + r->wait = NULL; + sched_queue(w); } } + spin_release_irqrestore(&g_raw_lock, &irq); }