7
7
//! [`include/linux/skbuff.h`](../../../../include/linux/skbuff.h).
8
8
9
9
use crate :: {
10
- bindings, device, error:: code:: ENOMEM , str:: CStr , to_result, types:: PointerWrapper , ARef ,
11
- AlwaysRefCounted , Error , Result ,
10
+ bindings, device,
11
+ error:: { code:: ENOMEM , from_kernel_result} ,
12
+ str:: CStr ,
13
+ to_result,
14
+ types:: PointerWrapper ,
15
+ ARef , AlwaysRefCounted , Error , Result ,
12
16
} ;
13
17
use core:: {
14
18
cell:: UnsafeCell ,
@@ -50,67 +54,80 @@ impl Device {
50
54
51
55
/// Sets carrier.
52
56
pub fn netif_carrier_on ( & self ) {
57
+ // SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
53
58
unsafe { bindings:: netif_carrier_on ( self . 0 . get ( ) ) }
54
59
}
55
60
56
61
/// Clears carrier.
57
62
pub fn netif_carrier_off ( & self ) {
63
+ // SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
58
64
unsafe { bindings:: netif_carrier_off ( self . 0 . get ( ) ) }
59
65
}
60
66
61
67
/// Assigns Ethernet address to a net_device.
62
68
pub fn eth_hw_addr_set ( & self , addr : & [ u8 ; 6 ] ) {
69
+ // SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
63
70
unsafe { bindings:: eth_hw_addr_set ( self . 0 . get ( ) , addr as _ ) }
64
71
}
65
72
66
73
/// Returns the mtu of the device.
67
74
pub fn mtu_get ( & self ) -> u32 {
75
+ // SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
68
76
unsafe { addr_of ! ( ( * self . 0 . get( ) ) . mtu) . read ( ) }
69
77
}
70
78
71
79
/// Sets the max mtu of the device.
72
80
pub fn max_mtu_set ( & self , max_mtu : u32 ) {
81
+ // SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
73
82
unsafe { addr_of_mut ! ( ( * self . 0 . get( ) ) . max_mtu) . write ( max_mtu) } ;
74
83
}
75
84
76
85
/// Sets the minimum mtu of the device.
77
86
pub fn min_mtu_set ( & self , min_mtu : u32 ) {
87
+ // SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
78
88
unsafe { addr_of_mut ! ( ( * self . 0 . get( ) ) . min_mtu) . write ( min_mtu) } ;
79
89
}
80
90
81
91
/// Returns the flags of the device.
82
92
pub fn flags_get ( & self ) -> u32 {
93
+ // SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
83
94
unsafe { addr_of ! ( ( * self . 0 . get( ) ) . flags) . read ( ) }
84
95
}
85
96
86
97
/// Sets the priv_flags of the device.
87
98
pub fn priv_flags_get ( & self ) -> u64 {
99
+ // SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
88
100
unsafe { addr_of ! ( ( * self . 0 . get( ) ) . priv_flags) . read ( ) }
89
101
}
90
102
91
103
/// Returns the priv_flags of the device.
92
104
pub fn priv_flags_set ( & self , flags : u64 ) {
105
+ // SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
93
106
unsafe { addr_of_mut ! ( ( * self . 0 . get( ) ) . priv_flags) . write ( flags) }
94
107
}
95
108
96
109
/// Reports the number of bytes queued to hardware.
97
110
pub fn sent_queue ( & self , bytes : u32 ) {
111
+ // SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
98
112
unsafe { bindings:: netdev_sent_queue ( self . 0 . get ( ) , bytes) }
99
113
}
100
114
101
115
/// Allows the upper layers to transmit.
102
116
pub fn netif_start_queue ( & self ) {
117
+ // SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
103
118
unsafe { bindings:: netif_start_queue ( self . 0 . get ( ) ) }
104
119
}
105
120
106
121
/// Stop the upper layers to transmit.
107
122
pub fn netif_stop_queue ( & self ) {
123
+ // SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
108
124
unsafe { bindings:: netif_stop_queue ( self . 0 . get ( ) ) }
109
125
}
110
126
111
127
/// Allocate an skbuff for rx on the device.
112
128
/// with IP header placed at an aligned offset.
113
129
pub fn alloc_skb_ip_align ( & self , length : u32 ) -> Result < ARef < SkBuff > > {
130
+ // SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
114
131
let skb = unsafe { bindings:: netdev_alloc_skb_ip_align ( self . 0 . get ( ) , length) } ;
115
132
if skb. is_null ( ) {
116
133
Err ( ENOMEM )
@@ -130,10 +147,12 @@ pub struct Registration<T: DeviceOperations> {
130
147
impl < T : DeviceOperations > Registration < T > {
131
148
/// Creates new instance of registration.
132
149
pub fn try_new ( parent : & dyn device:: RawDevice ) -> Result < Self > {
150
+ // SAFETY: FFI call.
133
151
let dev = unsafe { bindings:: alloc_etherdev_mqs ( 0 , 1 , 1 ) } ;
134
152
if dev. is_null ( ) {
135
153
Err ( ENOMEM )
136
154
} else {
155
+ // SAFETY: `dev` was allocated during initialization and is guaranteed to be valid.
137
156
unsafe { ( * dev) . dev . parent = parent. raw_device ( ) }
138
157
Ok ( Registration {
139
158
dev,
@@ -151,13 +170,20 @@ impl<T: DeviceOperations> Registration<T> {
151
170
152
171
/// Register a network device.
153
172
pub fn register ( & mut self , data : T :: Data ) -> Result {
154
- unsafe { ( * self . dev ) . netdev_ops = Self :: build_device_ops ( ) }
155
- let ret = unsafe { bindings:: register_netdev ( self . dev ) } ;
173
+ // SAFETY: `dev` was allocated during initialization and is guaranteed to be valid.
174
+ let ret = unsafe {
175
+ ( * self . dev ) . netdev_ops = Self :: build_device_ops ( ) ;
176
+ bindings:: register_netdev ( self . dev )
177
+ } ;
156
178
if ret != 0 {
157
179
Err ( Error :: from_kernel_errno ( ret) )
158
180
} else {
159
181
self . registered = true ;
160
182
unsafe {
183
+ // SAFETY: The C contract guarantees that `data` is available
184
+ // for implementers of the net_device operations (no other C code accesses
185
+ // it), so we know that there are no concurrent threads/CPUs accessing
186
+ // it (it's not visible to any other Rust code).
161
187
bindings:: dev_set_drvdata ( & mut ( * self . dev ) . dev , data. into_pointer ( ) as _ ) ;
162
188
}
163
189
Ok ( ( ) )
@@ -167,10 +193,13 @@ impl<T: DeviceOperations> Registration<T> {
167
193
168
194
impl < T : DeviceOperations > Drop for Registration < T > {
169
195
fn drop ( & mut self ) {
170
- if self . registered {
171
- unsafe { bindings:: unregister_netdev ( self . dev ) }
196
+ // SAFETY: `dev` was allocated during initialization and guaranteed to be valid.
197
+ unsafe {
198
+ if self . registered {
199
+ bindings:: unregister_netdev ( self . dev ) ;
200
+ }
201
+ bindings:: free_netdev ( self . dev ) ;
172
202
}
173
- unsafe { bindings:: free_netdev ( self . dev ) }
174
203
}
175
204
}
176
205
@@ -287,36 +316,55 @@ impl<T: DeviceOperations> Registration<T> {
287
316
ndo_get_tstamp : None ,
288
317
} ;
289
318
290
- const unsafe fn build_device_ops ( ) -> & ' static bindings:: net_device_ops {
319
+ const fn build_device_ops ( ) -> & ' static bindings:: net_device_ops {
291
320
& Self :: DEVICE_OPS
292
321
}
293
322
294
323
unsafe extern "C" fn open_callback ( netdev : * mut bindings:: net_device ) -> core:: ffi:: c_int {
295
- let ptr = unsafe { bindings:: dev_get_drvdata ( & mut ( * netdev) . dev ) } ;
296
- let dev = unsafe { Device :: from_ptr ( netdev) } ;
297
- let data = unsafe { T :: Data :: borrow ( ptr) } ;
298
- T :: open ( dev, data)
324
+ from_kernel_result ! {
325
+ // SAFETY: The C API guarantees that `net_device` isn't released while this function is running.
326
+ let dev = unsafe { Device :: from_ptr( netdev) } ;
327
+ // SAFETY: The value stored as driver data was returned by `into_pointer` during registration.
328
+ let data = unsafe { T :: Data :: borrow( bindings:: dev_get_drvdata( & mut ( * netdev) . dev) ) } ;
329
+ T :: open( dev, data) ?;
330
+ Ok ( 0 )
331
+ }
299
332
}
300
333
301
334
unsafe extern "C" fn stop_callback ( netdev : * mut bindings:: net_device ) -> core:: ffi:: c_int {
302
- let ptr = unsafe { bindings:: dev_get_drvdata ( & mut ( * netdev) . dev ) } ;
303
- let dev = unsafe { Device :: from_ptr ( netdev) } ;
304
- let data = unsafe { T :: Data :: borrow ( ptr) } ;
305
- T :: stop ( dev, data)
335
+ from_kernel_result ! {
336
+ // SAFETY: The C API guarantees that `net_device` isn't released while this function is running.
337
+ let dev = unsafe { Device :: from_ptr( netdev) } ;
338
+ // SAFETY: The value stored as driver data was returned by `into_pointer` during registration.
339
+ let data = unsafe { T :: Data :: borrow( bindings:: dev_get_drvdata( & mut ( * netdev) . dev) ) } ;
340
+ T :: stop( dev, data) ?;
341
+ Ok ( 0 )
342
+ }
306
343
}
307
344
308
345
unsafe extern "C" fn start_xmit_callback (
309
346
skb : * mut bindings:: sk_buff ,
310
347
netdev : * mut bindings:: net_device ,
311
- ) -> core :: ffi :: c_int {
312
- let ptr = unsafe { bindings :: dev_get_drvdata ( & mut ( * netdev ) . dev ) } ;
348
+ ) -> bindings :: netdev_tx_t {
349
+ // SAFETY: The C API guarantees that `net_device` isn't released while this function is running.
313
350
let dev = unsafe { Device :: from_ptr ( netdev) } ;
351
+ // SAFETY: The C API guarantees that `sk_buff` isn't released while this function is running.
314
352
let skb = unsafe { SkBuff :: from_ptr ( skb) } ;
315
- let data = unsafe { T :: Data :: borrow ( ptr) } ;
316
- T :: start_xmit ( skb, dev, data)
353
+ // SAFETY: The value stored as driver data was returned by `into_pointer` during registration.
354
+ let data = unsafe { T :: Data :: borrow ( bindings:: dev_get_drvdata ( & mut ( * netdev) . dev ) ) } ;
355
+ T :: start_xmit ( skb, dev, data) as bindings:: netdev_tx_t
317
356
}
318
357
}
319
358
359
+ /// Driver transmit return codes.
360
+ #[ repr( i32 ) ]
361
+ pub enum NetdevTx {
362
+ /// Driver took care of packet.
363
+ Ok = bindings:: netdev_tx_NETDEV_TX_OK,
364
+ /// Driver tx path was busy.
365
+ Busy = bindings:: netdev_tx_NETDEV_TX_BUSY,
366
+ }
367
+
320
368
// SAFETY: `Registration` does not expose any of its state across threads.
321
369
unsafe impl < T : DeviceOperations > Sync for Registration < T > { }
322
370
@@ -332,17 +380,17 @@ pub trait DeviceOperations {
332
380
type Data : PointerWrapper + Send + Sync = ( ) ;
333
381
334
382
/// Corresponds to `ndo_open` in `struct net_device_ops`.
335
- fn open ( dev : & Device , data : <Self :: Data as PointerWrapper >:: Borrowed < ' _ > ) -> i32 ;
383
+ fn open ( dev : & Device , data : <Self :: Data as PointerWrapper >:: Borrowed < ' _ > ) -> Result ;
336
384
337
385
/// Corresponds to `ndo_stop` in `struct net_device_ops`.
338
- fn stop ( dev : & Device , data : <Self :: Data as PointerWrapper >:: Borrowed < ' _ > ) -> i32 ;
386
+ fn stop ( dev : & Device , data : <Self :: Data as PointerWrapper >:: Borrowed < ' _ > ) -> Result ;
339
387
340
388
/// Corresponds to `ndo_start_xmit` in `struct net_device_ops`.
341
389
fn start_xmit (
342
390
skb : & SkBuff ,
343
391
dev : & Device ,
344
392
data : <Self :: Data as PointerWrapper >:: Borrowed < ' _ > ,
345
- ) -> i32 ;
393
+ ) -> NetdevTx ;
346
394
}
347
395
348
396
/// Wraps the kernel's `struct net`.
0 commit comments