1- use super :: { Config , EthernetAddress , Features , VirtioNetHdr } ;
2- use super :: { MIN_BUFFER_LEN , NET_HDR_SIZE , QUEUE_RECEIVE , QUEUE_TRANSMIT , SUPPORTED_FEATURES } ;
1+ use super :: { Config , EthernetAddress , Features , VirtioNetHdr , VirtioNetHdrLegacy } ;
2+ use super :: { MIN_BUFFER_LEN , QUEUE_RECEIVE , QUEUE_TRANSMIT , SUPPORTED_FEATURES } ;
33use crate :: config:: read_config;
44use crate :: hal:: Hal ;
55use crate :: queue:: VirtQueue ;
66use crate :: transport:: { InterruptStatus , Transport } ;
77use crate :: { Error , Result } ;
8+ use core:: mem:: size_of;
89use log:: { debug, info, warn} ;
910use zerocopy:: IntoBytes ;
1011
@@ -21,6 +22,8 @@ pub struct VirtIONetRaw<H: Hal, T: Transport, const QUEUE_SIZE: usize> {
2122 mac : EthernetAddress ,
2223 recv_queue : VirtQueue < H , QUEUE_SIZE > ,
2324 send_queue : VirtQueue < H , QUEUE_SIZE > ,
25+ /// Whether `num_buffers` is missing in the `virtio_net_hdr` struct.
26+ pub ( crate ) legacy_header : bool ,
2427}
2528
2629impl < H : Hal , T : Transport , const QUEUE_SIZE : usize > VirtIONetRaw < H , T , QUEUE_SIZE > {
@@ -54,6 +57,8 @@ impl<H: Hal, T: Transport, const QUEUE_SIZE: usize> VirtIONetRaw<H, T, QUEUE_SIZ
5457 mac,
5558 recv_queue,
5659 send_queue,
60+ legacy_header : !negotiated_features. contains ( Features :: VERSION_1 )
61+ && !negotiated_features. contains ( Features :: MRG_RXBUF ) ,
5762 } )
5863 }
5964
@@ -95,8 +100,13 @@ impl<H: Hal, T: Transport, const QUEUE_SIZE: usize> VirtIONetRaw<H, T, QUEUE_SIZ
95100 }
96101
97102 /// Whether the length of the transmit buffer is valid.
98- fn check_tx_buf_len ( tx_buf : & [ u8 ] ) -> Result < ( ) > {
99- if tx_buf. len ( ) < NET_HDR_SIZE {
103+ fn check_tx_buf_len ( & self , tx_buf : & [ u8 ] ) -> Result < ( ) > {
104+ let hdr_size = if self . legacy_header {
105+ size_of :: < VirtioNetHdrLegacy > ( )
106+ } else {
107+ size_of :: < VirtioNetHdr > ( )
108+ } ;
109+ if tx_buf. len ( ) < hdr_size {
100110 warn ! ( "Transmit buffer len {} is too small" , tx_buf. len( ) ) ;
101111 Err ( Error :: InvalidParam )
102112 } else {
@@ -108,12 +118,21 @@ impl<H: Hal, T: Transport, const QUEUE_SIZE: usize> VirtIONetRaw<H, T, QUEUE_SIZ
108118 ///
109119 /// If the `buffer` is not large enough, it returns [`Error::InvalidParam`].
110120 pub fn fill_buffer_header ( & self , buffer : & mut [ u8 ] ) -> Result < usize > {
111- if buffer. len ( ) < NET_HDR_SIZE {
112- return Err ( Error :: InvalidParam ) ;
121+ macro_rules! fill {
122+ ( $hdr: ty) => { {
123+ if buffer. len( ) < size_of:: <$hdr>( ) {
124+ return Err ( Error :: InvalidParam ) ;
125+ }
126+ let header = <$hdr>:: default ( ) ;
127+ buffer[ ..size_of:: <$hdr>( ) ] . copy_from_slice( header. as_bytes( ) ) ;
128+ Ok ( size_of:: <$hdr>( ) )
129+ } } ;
130+ }
131+ if self . legacy_header {
132+ fill ! ( VirtioNetHdrLegacy )
133+ } else {
134+ fill ! ( VirtioNetHdr )
113135 }
114- let header = VirtioNetHdr :: default ( ) ;
115- buffer[ ..NET_HDR_SIZE ] . copy_from_slice ( header. as_bytes ( ) ) ;
116- Ok ( NET_HDR_SIZE )
117136 }
118137
119138 /// Submits a request to transmit a buffer immediately without waiting for
@@ -141,7 +160,7 @@ impl<H: Hal, T: Transport, const QUEUE_SIZE: usize> VirtIONetRaw<H, T, QUEUE_SIZ
141160 /// [`poll_transmit`]: Self::poll_transmit
142161 /// [`transmit_complete`]: Self::transmit_complete
143162 pub unsafe fn transmit_begin ( & mut self , tx_buf : & [ u8 ] ) -> Result < u16 > {
144- Self :: check_tx_buf_len ( tx_buf) ?;
163+ self . check_tx_buf_len ( tx_buf) ?;
145164 let token = self . send_queue . add ( & [ tx_buf] , & mut [ ] ) ?;
146165 if self . send_queue . should_notify ( ) {
147166 self . transport . notify ( QUEUE_TRANSMIT ) ;
@@ -226,28 +245,42 @@ impl<H: Hal, T: Transport, const QUEUE_SIZE: usize> VirtIONetRaw<H, T, QUEUE_SIZ
226245 rx_buf : & mut [ u8 ] ,
227246 ) -> Result < ( usize , usize ) > {
228247 let len = self . recv_queue . pop_used ( token, & [ ] , & mut [ rx_buf] ) ? as usize ;
229- let packet_len = len. checked_sub ( NET_HDR_SIZE ) . ok_or ( Error :: IoError ) ?;
230- Ok ( ( NET_HDR_SIZE , packet_len) )
248+ let hdr_size = if self . legacy_header {
249+ size_of :: < VirtioNetHdrLegacy > ( )
250+ } else {
251+ size_of :: < VirtioNetHdr > ( )
252+ } ;
253+ let packet_len = len. checked_sub ( hdr_size) . ok_or ( Error :: IoError ) ?;
254+ Ok ( ( hdr_size, packet_len) )
231255 }
232256
233257 /// Sends a packet to the network, and blocks until the request completed.
234258 pub fn send ( & mut self , tx_buf : & [ u8 ] ) -> Result {
235- let header = VirtioNetHdr :: default ( ) ;
236- if tx_buf. is_empty ( ) {
237- // Special case sending an empty packet, to avoid adding an empty buffer to the
238- // virtqueue.
239- self . send_queue . add_notify_wait_pop (
240- & [ header. as_bytes ( ) ] ,
241- & mut [ ] ,
242- & mut self . transport ,
243- ) ?;
244- } else {
245- self . send_queue . add_notify_wait_pop (
246- & [ header. as_bytes ( ) , tx_buf] ,
247- & mut [ ] ,
248- & mut self . transport ,
249- ) ?;
259+ macro_rules! send {
260+ ( $header: expr) => { {
261+ let header = $header;
262+ if tx_buf. is_empty( ) {
263+ // Special case sending an empty packet, to avoid adding an empty buffer to the
264+ // virtqueue.
265+ self . send_queue. add_notify_wait_pop(
266+ & [ header. as_bytes( ) ] ,
267+ & mut [ ] ,
268+ & mut self . transport,
269+ ) ?;
270+ } else {
271+ self . send_queue. add_notify_wait_pop(
272+ & [ header. as_bytes( ) , tx_buf] ,
273+ & mut [ ] ,
274+ & mut self . transport,
275+ ) ?;
276+ }
277+ } } ;
250278 }
279+ if self . legacy_header {
280+ send ! ( VirtioNetHdrLegacy :: default ( ) )
281+ } else {
282+ send ! ( VirtioNetHdr :: default ( ) )
283+ } ;
251284 Ok ( ( ) )
252285 }
253286
0 commit comments