diff --git a/src/include/ipxe/netdevice.h b/src/include/ipxe/netdevice.h index 4649377a..26e2ab89 100644 --- a/src/include/ipxe/netdevice.h +++ b/src/include/ipxe/netdevice.h @@ -343,6 +343,9 @@ struct net_device { /** Network device interrupts are enabled */ #define NETDEV_IRQ_ENABLED 0x0002 +/** Network device receive queue processing is frozen */ +#define NETDEV_RX_FROZEN 0x0004 + /** Link-layer protocol table */ #define LL_PROTOCOLS __table ( struct ll_protocol, "ll_protocols" ) @@ -505,7 +508,7 @@ netdev_link_ok ( struct net_device *netdev ) { * Check whether or not network device is open * * @v netdev Network device - * @v is_open Network device is open + * @ret is_open Network device is open */ static inline __attribute__ (( always_inline )) int netdev_is_open ( struct net_device *netdev ) { @@ -516,13 +519,24 @@ netdev_is_open ( struct net_device *netdev ) { * Check whether or not network device interrupts are currently enabled * * @v netdev Network device - * @v irq_enabled Network device interrupts are enabled + * @ret irq_enabled Network device interrupts are enabled */ static inline __attribute__ (( always_inline )) int netdev_irq_enabled ( struct net_device *netdev ) { return ( netdev->state & NETDEV_IRQ_ENABLED ); } +/** + * Check whether or not network device receive queue processing is frozen + * + * @v netdev Network device + * @ret rx_frozen Network device receive queue processing is frozen + */ +static inline __attribute__ (( always_inline )) int +netdev_rx_frozen ( struct net_device *netdev ) { + return ( netdev->state & NETDEV_RX_FROZEN ); +} + extern void netdev_link_err ( struct net_device *netdev, int rc ); extern void netdev_link_down ( struct net_device *netdev ); extern int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ); @@ -550,6 +564,7 @@ extern int net_tx ( struct io_buffer *iobuf, struct net_device *netdev, extern int net_rx ( struct io_buffer *iobuf, struct net_device *netdev, uint16_t net_proto, const void *ll_dest, const void *ll_source ); +extern void net_poll ( void ); /** * Complete network transmission @@ -585,4 +600,24 @@ netdev_link_up ( struct net_device *netdev ) { netdev_link_err ( netdev, 0 ); } +/** + * Freeze network device receive queue processing + * + * @v netdev Network device + */ +static inline __attribute__ (( always_inline )) void +netdev_rx_freeze ( struct net_device *netdev ) { + netdev->state |= NETDEV_RX_FROZEN; +} + +/** + * Unfreeze network device receive queue processing + * + * @v netdev Network device + */ +static inline __attribute__ (( always_inline )) void +netdev_rx_unfreeze ( struct net_device *netdev ) { + netdev->state &= ~NETDEV_RX_FROZEN; +} + #endif /* _IPXE_NETDEVICE_H */ diff --git a/src/net/netdevice.c b/src/net/netdevice.c index c6c377b5..90dab8fb 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -669,14 +669,12 @@ int net_rx ( struct io_buffer *iobuf, struct net_device *netdev, } /** - * Single-step the network stack - * - * @v process Network stack process + * Poll the network stack * * This polls all interfaces for received packets, and processes * packets from the RX queue. */ -static void net_step ( struct process *process __unused ) { +void net_poll ( void ) { struct net_device *netdev; struct io_buffer *iobuf; struct ll_protocol *ll_protocol; @@ -691,6 +689,15 @@ static void net_step ( struct process *process __unused ) { /* Poll for new packets */ netdev_poll ( netdev ); + /* Leave received packets on the queue if receive + * queue processing is currently frozen. This will + * happen when the raw packets are to be manually + * dequeued using netdev_rx_dequeue(), rather than + * processed via the usual networking stack. + */ + if ( netdev_rx_frozen ( netdev ) ) + continue; + /* Process at most one received packet. Give priority * to getting packets out of the NIC over processing * the received packets, because we advertise a window @@ -723,6 +730,15 @@ static void net_step ( struct process *process __unused ) { } } +/** + * Single-step the network stack + * + * @v process Network stack process + */ +static void net_step ( struct process *process __unused ) { + net_poll(); +} + /** Networking stack process */ struct process net_process __permanent_process = { .list = LIST_HEAD_INIT ( net_process.list ),