diff --git a/drivers/net/dummy_rs.rs b/drivers/net/dummy_rs.rs index 708e029efbef51..28dbfc4f84da94 100644 --- a/drivers/net/dummy_rs.rs +++ b/drivers/net/dummy_rs.rs @@ -11,7 +11,7 @@ #![no_std] #![feature(allocator_api, global_asm)] -use kernel::prelude::*; +use kernel::{net::netlink::{NlAttrVec, NlExtAck}, prelude::*}; use kernel::net::prelude::*; use kernel::net::device; @@ -60,6 +60,15 @@ fn setup(dev: &mut NetDevice) { dev.set_mtu(0, 0); } +fn validate(tb: &NlAttrVec, data: &NlAttrVec, ext_ack: &NlExtAck) -> KernelResult<()> { + if let Some(addr) = tb.get(kernel::bindings::IFLA_ADDRESS) { + if addr.nla_len() != kernel::binding::ETH_ALEN { + return Err(0) + } + } + Ok(()) +} + rtnl_link_ops! { kind: b"dummy_rs", type: DummyRsDev, @@ -79,7 +88,8 @@ impl KernelModule for RustNetDummy { pr_info!("Rust Network Dummy with {} pseudo devices\n", numdummies.read(&lock)); } - let dev = NetDevice::new(DummyRsDev, kernel::cstr!("dummyrs%d"), kernel::net::device::NetNameAssingType::Enum, 1, 1)?; + let mut dev = NetDevice::new(DummyRsDev, kernel::cstr!("dummyrs%d"), kernel::net::device::NetNameAssingType::Enum, 1, 1)?; + dev.set_rtnl_ops( unsafe { &dummy_rs_rtnl_link_ops }); if let Err(e) = dev.register() { pr_warn!("could not register: {}", e.to_kernel_errno()); @@ -122,9 +132,8 @@ impl NetDeviceAdapter for DummyRsDev { fn setup(dev: &mut NetDevice) { pr_info!("called netdev_setup"); - //dev.rtnl_link_ops = unsafe { &dummy_rs_rtnl_link_ops as *const kernel::bindings::rtnl_link_ops as *mut _ }; - dev.set_rtnl_ops( unsafe { &dummy_rs_rtnl_link_ops }); - + setup(dev); + //dev.set_rtnl_ops( unsafe { &dummy_rs_rtnl_link_ops }); } } diff --git a/rust/generate_rust_analyzer.sh b/rust/generate_rust_analyzer.sh index 1b4129b4727690..1b8a7300da6d70 100755 --- a/rust/generate_rust_analyzer.sh +++ b/rust/generate_rust_analyzer.sh @@ -21,7 +21,7 @@ function generate_crate() { module=$2 member=${3:-"true"} cfg=${4:-$(generate_cfgs)} - deps=${5:-'[{"crate":0,"name":"core"},{"crate":2,"name":"alloc"},{"crate":3,"name":"kernel"}]'} + deps=${5:-'[{"crate":0,"name":"core"},{"crate":2,"name":"alloc"},{"crate":4,"name":"kernel"}]'} extra=${EXTRA:-""} echo "{ @@ -43,9 +43,6 @@ function generate_kernel() { generate_crate "alloc" "${lib_src}/alloc/src/lib.rs" "false" "[]" \ '[{"crate":0,"name":"core"},{"crate":1,"name":"compiler_builtins"}]' echo "," - EXTRA=$dylib_and_extra generate_crate "kernel" "${srctree}/rust/kernel/lib.rs" "true" "$(generate_cfgs)" \ - '[{"crate":0,"name":"core"},{"crate":2,"name":"alloc"}]' - echo "," echo '{ "display_name":"module", "root_module":"'${srctree}'/rust/module.rs", @@ -54,7 +51,10 @@ function generate_kernel() { "deps": [], "cfg": [] },' - generate_crate "module" "${srctree}/rust/module.rs" + EXTRA=$dylib_and_extra generate_crate "kernel" "${srctree}/rust/kernel/lib.rs" "true" "$(generate_cfgs)" \ + '[{"crate":0,"name":"core"},{"crate":2,"name":"alloc"},{"crate":3,"name":"module"}]' + #echo "," + #generate_crate "module" "${srctree}/rust/module.rs" echo "," } diff --git a/rust/kernel/net/device.rs b/rust/kernel/net/device.rs index 9c978ce5532464..a8060bf4ff0b04 100644 --- a/rust/kernel/net/device.rs +++ b/rust/kernel/net/device.rs @@ -76,21 +76,26 @@ unsafe impl Sync for NetDevice {} impl NetDevice { pub fn new(priv_data: T, format_name: CStr<'static>, name_assign_type: NetNameAssingType, txqs: u32, rxqs: u32) -> KernelResult { + let _lock = RtnlLock::lock(); + // Lock is hold + let dev = unsafe { Self::new_locked(priv_data, format_name, name_assign_type, txqs, rxqs) }; + dev + } + + pub unsafe fn new_locked(priv_data: T, format_name: CStr<'static>, name_assign_type: NetNameAssingType, txqs: u32, rxqs: u32) -> KernelResult { // TODO: check for {t,r}xqs bigger 0 let size = mem::size_of::() as i32; // Safety: TODO - let ptr = unsafe { bindings::alloc_netdev_mqs(size, format_name.as_ptr() as _, name_assign_type as u8, Some(setup_netdev_callback::), txqs, rxqs) }; + let ptr = bindings::alloc_netdev_mqs(size, format_name.as_ptr() as _, name_assign_type as u8, Some(setup_netdev_callback::), txqs, rxqs); if ptr.is_null() { return Err(Error::ENOMEM); } if size != 0 { // Safety: T is valid and dest is created by alloc_netdev_mqs - unsafe { - let dest = rust_helper_netdev_priv(ptr) as *mut T; - ptr::write(dest, priv_data); - } + let dest = rust_helper_netdev_priv(ptr) as *mut T; + ptr::write(dest, priv_data); } Ok(Self { diff --git a/rust/kernel/net/mod.rs b/rust/kernel/net/mod.rs index 19cf4a44f708f9..9c26f3845d6370 100644 --- a/rust/kernel/net/mod.rs +++ b/rust/kernel/net/mod.rs @@ -2,6 +2,7 @@ pub mod device; pub mod ethtool; pub mod rtnl; +pub mod netlink; #[doc(inline)] pub use module::rtnl_link_ops; diff --git a/rust/kernel/net/netlink.rs b/rust/kernel/net/netlink.rs new file mode 100644 index 00000000000000..255adad608c24d --- /dev/null +++ b/rust/kernel/net/netlink.rs @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0 +use alloc::vec::Vec; +use core::ops::{Deref, DerefMut}; + +use crate::{bindings, linked_list::Wrapper}; +use crate::{c_types, CStr}; +use crate::error::{Error, KernelResult}; +use crate::sync::Lock; +use crate::user_ptr::{UserSlicePtr, UserSlicePtrReader, UserSlicePtrWriter}; + +use super::device::{NetDeviceAdapter, NetDevice}; + + +/*#[repr(C)] +pub struct NlAttr { + nla_len: u16, + nla_type: u16, +}*/ +pub struct NlAttr(*const bindings::nlattr); + +impl NlAttr { + pub fn is_null(&self) -> bool { + self.0.is_null() + } + + pub fn nla_len(&self) -> u16 { + if self.is_null() { + return 0; + } + + // NO-PANIC: self is valid and not null + let nlattr = self.0.as_ref().unwrap(); + nlattr.nla_len - bindings::NLA_HDRLEN + } + + /// Constructs a new [`struct nlattr`] wrapper. + /// + /// # Safety + /// + /// The pointer `ptr` must be non-null and valid for the lifetime of the object. + pub unsafe fn from_ptr(ptr: *const bindings::nlattr) -> Self { + Self(ptr) + } + /*pub unsafe fn from_ptr(ptr: *const bindings::nlattr) -> &'static mut Self { + (ptr as *mut NlAttr).as_mut().unwrap() + }*/ +} + +pub struct NlExtAck(*const bindings::netlink_ext_ack); + +impl NlExtAck { + /// Constructs a new [`struct netlink_ext_ack`] wrapper. + /// + /// # Safety + /// + /// The pointer `ptr` must be non-null and valid for the lifetime of the object. + pub unsafe fn from_ptr(ptr: *const bindings::netlink_ext_ack) -> Self { + Self(ptr) + } +} + +pub struct NlAttrVec<'a>(&'a mut [NlAttr]); + +impl<'a> NlAttrVec<'a> { + pub fn get(&self, offset: u32) -> Option { + if offset > bindings::__IFLA_MAX { + return None; + } + + let nlattr = self.0[offset as usize]; + if nlattr.is_null() { + None + } else { + Some(nlattr) + } + } + + /// Constructs a new [`struct nlattr[]`] wrapper. + /// + /// # Safety + /// + /// The pointer `ptr` must be non-null and valid for the lifetime of the object. + /// The pointer `ptr` must be valid for the size of `__IFLA_MAX` * `mem::size_of` + pub unsafe fn from_ptr(ptr: *const bindings::nlattr) -> Self { + // TODO: is this correct? + Self(core::slice::from_raw_parts_mut(ptr as *mut NlAttr, bindings::__IFLA_MAX as usize)) + } +} \ No newline at end of file