mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-09 02:46:47 +00:00
Merge pull request #980 from val213/feat-network-rebuild
remove(uevent): 将 netlink/uevent 机制从网络子分支中暂时移除
This commit is contained in:
commit
10e62c7a47
@ -22,8 +22,6 @@ use log::{debug, error, warn};
|
|||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
|
|
||||||
use super::{acpi_kset, AcpiManager};
|
use super::{acpi_kset, AcpiManager};
|
||||||
use crate::driver::base::uevent::kobject_uevent::kobject_uevent;
|
|
||||||
use crate::driver::base::uevent::KobjectAction;
|
|
||||||
static mut __HOTPLUG_KSET_INSTANCE: Option<Arc<KSet>> = None;
|
static mut __HOTPLUG_KSET_INSTANCE: Option<Arc<KSet>> = None;
|
||||||
static mut __ACPI_TABLES_KSET_INSTANCE: Option<Arc<KSet>> = None;
|
static mut __ACPI_TABLES_KSET_INSTANCE: Option<Arc<KSet>> = None;
|
||||||
static mut __ACPI_TABLES_DATA_KSET_INSTANCE: Option<Arc<KSet>> = None;
|
static mut __ACPI_TABLES_DATA_KSET_INSTANCE: Option<Arc<KSet>> = None;
|
||||||
@ -117,26 +115,6 @@ impl AcpiManager {
|
|||||||
self.acpi_table_data_init(&header)?;
|
self.acpi_table_data_init(&header)?;
|
||||||
}
|
}
|
||||||
// TODO:UEVENT
|
// TODO:UEVENT
|
||||||
unsafe {
|
|
||||||
let _ = kobject_uevent(
|
|
||||||
acpi_tables_kset.clone() as Arc<dyn KObject>,
|
|
||||||
KobjectAction::KOBJADD,
|
|
||||||
);
|
|
||||||
let _ = kobject_uevent(
|
|
||||||
__ACPI_TABLES_DATA_KSET_INSTANCE
|
|
||||||
.as_ref()
|
|
||||||
.map(|kset| kset.clone() as Arc<dyn KObject>)
|
|
||||||
.unwrap(),
|
|
||||||
KobjectAction::KOBJADD,
|
|
||||||
);
|
|
||||||
let _ = kobject_uevent(
|
|
||||||
__ACPI_TABLES_DYNAMIC_KSET_INSTANCE
|
|
||||||
.as_ref()
|
|
||||||
.map(|kset| kset.clone() as Arc<dyn KObject>)
|
|
||||||
.unwrap(),
|
|
||||||
KobjectAction::KOBJADD,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,19 +1,16 @@
|
|||||||
/// 引入Module
|
/// 引入Module
|
||||||
use crate::{
|
use crate::driver::{
|
||||||
driver::{
|
base::{
|
||||||
base::{
|
device::{
|
||||||
device::{
|
device_number::{DeviceNumber, Major},
|
||||||
device_number::{DeviceNumber, Major},
|
Device, DeviceError, IdTable, BLOCKDEVS,
|
||||||
Device, DeviceError, IdTable, BLOCKDEVS,
|
},
|
||||||
},
|
map::{
|
||||||
map::{
|
DeviceStruct, DEV_MAJOR_DYN_END, DEV_MAJOR_DYN_EXT_END, DEV_MAJOR_DYN_EXT_START,
|
||||||
DeviceStruct, DEV_MAJOR_DYN_END, DEV_MAJOR_DYN_EXT_END, DEV_MAJOR_DYN_EXT_START,
|
DEV_MAJOR_HASH_SIZE, DEV_MAJOR_MAX,
|
||||||
DEV_MAJOR_HASH_SIZE, DEV_MAJOR_MAX,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
block::cache::{cached_block_device::BlockCache, BlockCacheError, BLOCK_SIZE},
|
|
||||||
},
|
},
|
||||||
filesystem::sysfs::AttributeGroup,
|
block::cache::{cached_block_device::BlockCache, BlockCacheError, BLOCK_SIZE},
|
||||||
};
|
};
|
||||||
|
|
||||||
use alloc::{string::String, sync::Arc, vec::Vec};
|
use alloc::{string::String, sync::Arc, vec::Vec};
|
||||||
|
@ -2,8 +2,6 @@ use super::{
|
|||||||
bus::{bus_manager, Bus},
|
bus::{bus_manager, Bus},
|
||||||
Device, DeviceMatchName, DeviceMatcher, IdTable,
|
Device, DeviceMatchName, DeviceMatcher, IdTable,
|
||||||
};
|
};
|
||||||
use crate::driver::base::uevent::kobject_uevent::kobject_uevent;
|
|
||||||
use crate::driver::base::uevent::KobjectAction;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
driver::base::{
|
driver::base::{
|
||||||
device::{bus::BusNotifyEvent, dd::DeviceAttrCoredump, device_manager},
|
device::{bus::BusNotifyEvent, dd::DeviceAttrCoredump, device_manager},
|
||||||
@ -220,7 +218,6 @@ impl DriverManager {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
// todo: 发送uevent,类型问题
|
// todo: 发送uevent,类型问题
|
||||||
let _ = kobject_uevent(driver.clone() as Arc<dyn KObject>, KobjectAction::KOBJADD);
|
|
||||||
// deferred_probe_extend_timeout();
|
// deferred_probe_extend_timeout();
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -43,7 +43,6 @@ use super::{
|
|||||||
},
|
},
|
||||||
kset::KSet,
|
kset::KSet,
|
||||||
swnode::software_node_notify,
|
swnode::software_node_notify,
|
||||||
uevent::UeventAttr,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod bus;
|
pub mod bus;
|
||||||
@ -1026,25 +1025,6 @@ impl Eq for DeviceId {}
|
|||||||
|
|
||||||
impl IrqHandlerData for DeviceId {}
|
impl IrqHandlerData for DeviceId {}
|
||||||
|
|
||||||
/// sysfs下设备的通用属性组
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct CommonAttrGroup;
|
|
||||||
impl AttributeGroup for CommonAttrGroup {
|
|
||||||
fn name(&self) -> Option<&str> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
fn attrs(&self) -> &[&'static dyn Attribute] {
|
|
||||||
&[&UeventAttr]
|
|
||||||
}
|
|
||||||
fn is_visible(
|
|
||||||
&self,
|
|
||||||
_kobj: alloc::sync::Arc<dyn KObject>,
|
|
||||||
attr: &'static dyn Attribute,
|
|
||||||
) -> Option<crate::filesystem::vfs::syscall::ModeType> {
|
|
||||||
Some(attr.mode())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
/// class_dir列表,通过parent kobject的name和class_dir的name来索引class_dir实例
|
/// class_dir列表,通过parent kobject的name和class_dir的name来索引class_dir实例
|
||||||
static ref CLASS_DIR_KSET_INSTANCE: RwLock<BTreeMap<String, Arc<ClassDir>>> = RwLock::new(BTreeMap::new());
|
static ref CLASS_DIR_KSET_INSTANCE: RwLock<BTreeMap<String, Arc<ClassDir>>> = RwLock::new(BTreeMap::new());
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use core::{any::Any, fmt::Debug, hash::Hash, ops::Deref};
|
use core::{any::Any, fmt::Debug, hash::Hash, ops::Deref};
|
||||||
|
|
||||||
use alloc::{
|
use alloc::{
|
||||||
boxed::Box,
|
|
||||||
string::String,
|
string::String,
|
||||||
sync::{Arc, Weak},
|
sync::{Arc, Weak},
|
||||||
};
|
};
|
||||||
@ -22,7 +21,7 @@ use crate::{
|
|||||||
|
|
||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
|
|
||||||
use super::{device::CommonAttrGroup, kset::KSet, uevent::kobject_uevent};
|
use super::kset::KSet;
|
||||||
|
|
||||||
pub trait KObject: Any + Send + Sync + Debug + CastFromSync {
|
pub trait KObject: Any + Send + Sync + Debug + CastFromSync {
|
||||||
fn as_any_ref(&self) -> &dyn core::any::Any;
|
fn as_any_ref(&self) -> &dyn core::any::Any;
|
||||||
@ -263,7 +262,6 @@ impl KObjectManager {
|
|||||||
|
|
||||||
fn get_kobj_path_length(kobj: &Arc<dyn KObject>) -> usize {
|
fn get_kobj_path_length(kobj: &Arc<dyn KObject>) -> usize {
|
||||||
log::info!("get_kobj_path_length() kobj:{:?}", kobj.name());
|
log::info!("get_kobj_path_length() kobj:{:?}", kobj.name());
|
||||||
let mut length = 1;
|
|
||||||
let mut parent = kobj.parent().unwrap().upgrade().unwrap();
|
let mut parent = kobj.parent().unwrap().upgrade().unwrap();
|
||||||
/* walk up the ancestors until we hit the one pointing to the
|
/* walk up the ancestors until we hit the one pointing to the
|
||||||
* root.
|
* root.
|
||||||
|
@ -6,11 +6,8 @@ use alloc::{
|
|||||||
|
|
||||||
use core::hash::Hash;
|
use core::hash::Hash;
|
||||||
|
|
||||||
use super::{
|
use super::kobject::{
|
||||||
kobject::{
|
DynamicKObjKType, KObjType, KObject, KObjectManager, KObjectState, LockedKObjectState,
|
||||||
DynamicKObjKType, KObjType, KObject, KObjectManager, KObjectState, LockedKObjectState,
|
|
||||||
},
|
|
||||||
uevent::KobjUeventEnv,
|
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
filesystem::kernfs::KernFSInode,
|
filesystem::kernfs::KernFSInode,
|
||||||
@ -29,8 +26,6 @@ pub struct KSet {
|
|||||||
/// 与父节点有关的一些信息
|
/// 与父节点有关的一些信息
|
||||||
parent_data: RwLock<KSetParentData>,
|
parent_data: RwLock<KSetParentData>,
|
||||||
self_ref: Weak<KSet>,
|
self_ref: Weak<KSet>,
|
||||||
/// kset用于发送uevent的操作函数集。kset能够发送它所包含的各种子kobj、孙kobj的消息,即kobj或其父辈、爷爷辈,都可以发送消息;优先父辈,然后是爷爷辈,以此类推
|
|
||||||
pub uevent_ops: Option<Arc<dyn KSetUeventOps>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for KSet {
|
impl Hash for KSet {
|
||||||
@ -56,7 +51,6 @@ impl KSet {
|
|||||||
kobj_state: LockedKObjectState::new(None),
|
kobj_state: LockedKObjectState::new(None),
|
||||||
parent_data: RwLock::new(KSetParentData::new(None, None)),
|
parent_data: RwLock::new(KSetParentData::new(None, None)),
|
||||||
self_ref: Weak::default(),
|
self_ref: Weak::default(),
|
||||||
uevent_ops: Some(Arc::new(KSetUeventOpsDefault)),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let r = Arc::new(r);
|
let r = Arc::new(r);
|
||||||
@ -239,26 +233,3 @@ impl InnerKSet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/kobject.h#137
|
|
||||||
use core::fmt::Debug;
|
|
||||||
pub trait KSetUeventOps: Debug + Send + Sync {
|
|
||||||
fn filter(&self) -> Option<i32>;
|
|
||||||
fn uevent_name(&self) -> String;
|
|
||||||
fn uevent(&self, env: &KobjUeventEnv) -> i32;
|
|
||||||
}
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct KSetUeventOpsDefault;
|
|
||||||
|
|
||||||
impl KSetUeventOps for KSetUeventOpsDefault {
|
|
||||||
fn filter(&self) -> Option<i32> {
|
|
||||||
Some(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn uevent_name(&self) -> String {
|
|
||||||
String::new()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn uevent(&self, env: &KobjUeventEnv) -> i32 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -12,4 +12,3 @@ pub mod map;
|
|||||||
pub mod platform;
|
pub mod platform;
|
||||||
pub mod subsys;
|
pub mod subsys;
|
||||||
pub mod swnode;
|
pub mod swnode;
|
||||||
pub mod uevent;
|
|
||||||
|
@ -11,7 +11,7 @@ use crate::{
|
|||||||
bus::{Bus, BusState},
|
bus::{Bus, BusState},
|
||||||
device_manager,
|
device_manager,
|
||||||
driver::Driver,
|
driver::Driver,
|
||||||
CommonAttrGroup, Device, DeviceCommonData, DevicePrivateData, DeviceType, IdTable,
|
Device, DeviceCommonData, DevicePrivateData, DeviceType, IdTable,
|
||||||
},
|
},
|
||||||
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
||||||
kset::KSet,
|
kset::KSet,
|
||||||
@ -331,6 +331,6 @@ impl Device for PlatformBusDevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
||||||
Some(&[&CommonAttrGroup])
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,483 +0,0 @@
|
|||||||
// https://code.dragonos.org.cn/xref/linux-6.1.9/lib/kobject_uevent.c
|
|
||||||
use super::KObject;
|
|
||||||
use super::KobjUeventEnv;
|
|
||||||
use super::KobjectAction;
|
|
||||||
use super::{UEVENT_BUFFER_SIZE, UEVENT_NUM_ENVP};
|
|
||||||
use crate::driver::base::kobject::{KObjectManager, KObjectState};
|
|
||||||
use crate::init::initcall::INITCALL_POSTCORE;
|
|
||||||
use crate::libs::mutex::Mutex;
|
|
||||||
use crate::libs::rwlock::RwLock;
|
|
||||||
use crate::net::socket::netlink::af_netlink::netlink_has_listeners;
|
|
||||||
use crate::net::socket::netlink::af_netlink::NetlinkSocket;
|
|
||||||
use crate::net::socket::netlink::af_netlink::{netlink_broadcast, NetlinkSock};
|
|
||||||
use crate::net::socket::netlink::skbuff::SkBuff;
|
|
||||||
use crate::net::socket::netlink::{
|
|
||||||
netlink_kernel_create, NetlinkKernelCfg, NETLINK_KOBJECT_UEVENT, NL_CFG_F_NONROOT_RECV,
|
|
||||||
};
|
|
||||||
use alloc::boxed::Box;
|
|
||||||
use alloc::collections::LinkedList;
|
|
||||||
use alloc::string::{String, ToString};
|
|
||||||
use alloc::sync::Arc;
|
|
||||||
use alloc::vec::Vec;
|
|
||||||
use core::fmt::Write;
|
|
||||||
use num::Zero;
|
|
||||||
use system_error::SystemError;
|
|
||||||
use unified_init::macros::unified_init;
|
|
||||||
// 全局变量
|
|
||||||
pub static UEVENT_SEQNUM: u64 = 0;
|
|
||||||
// #ifdef CONFIG_UEVENT_HELPER
|
|
||||||
// char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
struct UeventSock {
|
|
||||||
inner: NetlinkSock,
|
|
||||||
}
|
|
||||||
impl UeventSock {
|
|
||||||
pub fn new(inner: NetlinkSock) -> Self {
|
|
||||||
UeventSock { inner }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 用于存储所有用于发送 uevent 消息的 netlink sockets。这些 sockets 用于在内核和用户空间之间传递设备事件通知。
|
|
||||||
// 每当需要发送 uevent 消息时,内核会遍历这个链表,并通过其中的每一个 socket 发送消息。
|
|
||||||
// 使用 Mutex 保护全局链表
|
|
||||||
lazy_static::lazy_static! {
|
|
||||||
static ref UEVENT_SOCK_LIST: Mutex<LinkedList<UeventSock>> = Mutex::new(LinkedList::new());
|
|
||||||
}
|
|
||||||
// 回调函数,当接收到 uevent 消息时调用
|
|
||||||
fn uevent_net_rcv() {
|
|
||||||
// netlink_rcv_skb(skb, &uevent_net_rcv_skb);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 内核初始化的时候,在设备初始化之前执行
|
|
||||||
#[unified_init(INITCALL_POSTCORE)]
|
|
||||||
fn kobejct_uevent_init() -> Result<(), SystemError> {
|
|
||||||
// todo: net namespace
|
|
||||||
return uevent_net_init();
|
|
||||||
}
|
|
||||||
// TODO:等net namespace实现后添加 net 参数和相关操作
|
|
||||||
// 内核启动的时候,即使没有进行网络命名空间的隔离也需要调用这个函数
|
|
||||||
// 支持 net namespace 之后需要在每个 net namespace 初始化的时候调用这个函数
|
|
||||||
/// 为每一个 net namespace 初始化 uevent
|
|
||||||
fn uevent_net_init() -> Result<(), SystemError> {
|
|
||||||
let cfg = NetlinkKernelCfg {
|
|
||||||
groups: 1,
|
|
||||||
flags: NL_CFG_F_NONROOT_RECV,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
// 创建一个内核 netlink socket
|
|
||||||
let ue_sk = UeventSock::new(netlink_kernel_create(NETLINK_KOBJECT_UEVENT, Some(cfg)).unwrap());
|
|
||||||
|
|
||||||
// todo: net namespace
|
|
||||||
// net.uevent_sock = ue_sk;
|
|
||||||
|
|
||||||
// 每个 net namespace 向链表中添加一个新的 uevent socket
|
|
||||||
UEVENT_SOCK_LIST.lock().push_back(ue_sk);
|
|
||||||
log::info!("uevent_net_init finish");
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 系统关闭时清理
|
|
||||||
fn uevent_net_exit() {
|
|
||||||
// 清理链表
|
|
||||||
UEVENT_SOCK_LIST.lock().clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// /* This lock protects uevent_seqnum and uevent_sock_list */
|
|
||||||
// static DEFINE_MUTEX(uevent_sock_mutex);
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
/// kobject_uevent,和kobject_uevent_env功能一样,只是没有指定任何的环境变量
|
|
||||||
pub fn kobject_uevent(kobj: Arc<dyn KObject>, action: KobjectAction) -> Result<(), SystemError> {
|
|
||||||
// kobject_uevent和kobject_uevent_env功能一样,只是没有指定任何的环境变量
|
|
||||||
match kobject_uevent_env(kobj, action, Vec::new()) {
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(e) => Err(e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// kobject_uevent_env,以envp为环境变量,上报一个指定action的uevent。环境变量的作用是为执行用户空间程序指定运行环境。
|
|
||||||
pub fn kobject_uevent_env(
|
|
||||||
kobj: Arc<dyn KObject>,
|
|
||||||
action: KobjectAction,
|
|
||||||
envp_ext: Vec<String>,
|
|
||||||
) -> Result<i32, SystemError> {
|
|
||||||
log::info!("kobject_uevent_env: kobj: {:?}, action: {:?}", kobj, action);
|
|
||||||
let mut state = KObjectState::empty();
|
|
||||||
let mut top_kobj = kobj.parent().unwrap().upgrade().unwrap();
|
|
||||||
let mut retval: i32;
|
|
||||||
let action_string = match action {
|
|
||||||
KobjectAction::KOBJADD => "add".to_string(),
|
|
||||||
KobjectAction::KOBJREMOVE => "remove".to_string(),
|
|
||||||
KobjectAction::KOBJCHANGE => "change".to_string(),
|
|
||||||
KobjectAction::KOBJMOVE => "move".to_string(),
|
|
||||||
KobjectAction::KOBJONLINE => "online".to_string(),
|
|
||||||
KobjectAction::KOBJOFFLINE => "offline".to_string(),
|
|
||||||
KobjectAction::KOBJBIND => "bind".to_string(),
|
|
||||||
KobjectAction::KOBJUNBIND => "unbind".to_string(),
|
|
||||||
};
|
|
||||||
/*
|
|
||||||
* Mark "remove" event done regardless of result, for some subsystems
|
|
||||||
* do not want to re-trigger "remove" event via automatic cleanup.
|
|
||||||
*/
|
|
||||||
if let KobjectAction::KOBJREMOVE = action {
|
|
||||||
log::info!("kobject_uevent_env: action: remove");
|
|
||||||
state.insert(KObjectState::REMOVE_UEVENT_SENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 不断向上查找,直到找到最顶层的kobject
|
|
||||||
while let Some(weak_parent) = top_kobj.parent() {
|
|
||||||
log::info!("kobject_uevent_env: top_kobj: {:?}", top_kobj);
|
|
||||||
top_kobj = weak_parent.upgrade().unwrap();
|
|
||||||
}
|
|
||||||
/* 查找当前kobject或其parent是否从属于某个kset;如果都不从属于某个kset,则返回错误。(说明一个kobject若没有加入kset,是不会上报uevent的) */
|
|
||||||
if kobj.kset().is_none() && top_kobj.kset().is_none() {
|
|
||||||
log::info!("attempted to send uevent without kset!\n");
|
|
||||||
return Err(SystemError::EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
let kset = top_kobj.kset();
|
|
||||||
// 判断该 kobject 的状态是否设置了uevent_suppress,如果设置了,则忽略所有的uevent上报并返回
|
|
||||||
if kobj.kobj_state().contains(KObjectState::UEVENT_SUPPRESS) {
|
|
||||||
log::info!("uevent_suppress caused the event to drop!");
|
|
||||||
return Ok(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果所属的kset的kset->filter返回的是0,过滤此次上报
|
|
||||||
if let Some(kset_ref) = kset.as_ref() {
|
|
||||||
if let Some(uevent_ops) = &kset_ref.uevent_ops {
|
|
||||||
if uevent_ops.filter() == Some(0) {
|
|
||||||
log::info!("filter caused the event to drop!");
|
|
||||||
return Ok(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 判断所属的kset是否有合法的名称(称作subsystem,和前期的内核版本有区别),否则不允许上报uevent
|
|
||||||
// originating subsystem
|
|
||||||
let subsystem: String = if let Some(kset_ref) = kset.as_ref() {
|
|
||||||
if let Some(uevent_ops) = &kset_ref.uevent_ops {
|
|
||||||
let name = uevent_ops.uevent_name();
|
|
||||||
if !name.is_empty() {
|
|
||||||
name
|
|
||||||
} else {
|
|
||||||
kobj.name()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
kobj.name()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
kobj.name()
|
|
||||||
};
|
|
||||||
if subsystem.is_empty() {
|
|
||||||
log::info!("unset subsystem caused the event to drop!");
|
|
||||||
}
|
|
||||||
log::info!("kobject_uevent_env: subsystem: {}", subsystem);
|
|
||||||
|
|
||||||
// 创建一个用于环境变量的缓冲区
|
|
||||||
let mut env = Box::new(KobjUeventEnv {
|
|
||||||
argv: Vec::with_capacity(UEVENT_NUM_ENVP),
|
|
||||||
envp: Vec::with_capacity(UEVENT_NUM_ENVP),
|
|
||||||
envp_idx: 0,
|
|
||||||
buf: vec![0; UEVENT_BUFFER_SIZE],
|
|
||||||
buflen: 0,
|
|
||||||
});
|
|
||||||
if env.buf.is_empty() {
|
|
||||||
log::error!("kobject_uevent_env: failed to allocate buffer");
|
|
||||||
return Err(SystemError::ENOMEM);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取设备的完整对象路径
|
|
||||||
let devpath: String = KObjectManager::kobject_get_path(&kobj);
|
|
||||||
log::info!("kobject_uevent_env: devpath: {}", devpath);
|
|
||||||
if devpath.is_empty() {
|
|
||||||
retval = SystemError::ENOENT.to_posix_errno();
|
|
||||||
// goto exit
|
|
||||||
drop(devpath);
|
|
||||||
drop(env);
|
|
||||||
log::warn!("kobject_uevent_env: devpath is empty");
|
|
||||||
return Ok(retval);
|
|
||||||
}
|
|
||||||
retval = add_uevent_var(&mut env, "ACTION=%s", &action_string).unwrap();
|
|
||||||
log::info!("kobject_uevent_env: retval: {}", retval);
|
|
||||||
if !retval.is_zero() {
|
|
||||||
drop(devpath);
|
|
||||||
drop(env);
|
|
||||||
log::info!("add_uevent_var failed ACTION");
|
|
||||||
return Ok(retval);
|
|
||||||
};
|
|
||||||
retval = add_uevent_var(&mut env, "DEVPATH=%s", &devpath).unwrap();
|
|
||||||
if !retval.is_zero() {
|
|
||||||
drop(devpath);
|
|
||||||
drop(env);
|
|
||||||
log::info!("add_uevent_var failed DEVPATH");
|
|
||||||
return Ok(retval);
|
|
||||||
};
|
|
||||||
retval = add_uevent_var(&mut env, "SUBSYSTEM=%s", &subsystem).unwrap();
|
|
||||||
if !retval.is_zero() {
|
|
||||||
drop(devpath);
|
|
||||||
drop(env);
|
|
||||||
log::info!("add_uevent_var failed SUBSYSTEM");
|
|
||||||
return Ok(retval);
|
|
||||||
};
|
|
||||||
|
|
||||||
/* keys passed in from the caller */
|
|
||||||
|
|
||||||
for var in envp_ext {
|
|
||||||
let retval = add_uevent_var(&mut env, "%s", &var).unwrap();
|
|
||||||
if !retval.is_zero() {
|
|
||||||
drop(devpath);
|
|
||||||
drop(env);
|
|
||||||
log::info!("add_uevent_var failed");
|
|
||||||
return Ok(retval);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(kset_ref) = kset.as_ref() {
|
|
||||||
if let Some(uevent_ops) = kset_ref.uevent_ops.as_ref() {
|
|
||||||
if uevent_ops.uevent(&env) != 0 {
|
|
||||||
retval = uevent_ops.uevent(&env);
|
|
||||||
if retval.is_zero() {
|
|
||||||
log::info!("kset uevent caused the event to drop!");
|
|
||||||
// goto exit
|
|
||||||
drop(devpath);
|
|
||||||
drop(env);
|
|
||||||
return Ok(retval);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
match action {
|
|
||||||
KobjectAction::KOBJADD => {
|
|
||||||
state.insert(KObjectState::ADD_UEVENT_SENT);
|
|
||||||
}
|
|
||||||
KobjectAction::KOBJUNBIND => {
|
|
||||||
zap_modalias_env(&mut env);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
//mutex_lock(&uevent_sock_mutex);
|
|
||||||
/* we will send an event, so request a new sequence number */
|
|
||||||
retval = add_uevent_var(&mut env, "SEQNUM=%llu", &(UEVENT_SEQNUM + 1).to_string()).unwrap();
|
|
||||||
if !retval.is_zero() {
|
|
||||||
drop(devpath);
|
|
||||||
drop(env);
|
|
||||||
log::info!("add_uevent_var failed");
|
|
||||||
return Ok(retval);
|
|
||||||
}
|
|
||||||
retval = kobject_uevent_net_broadcast(kobj, &env, &action_string, &devpath);
|
|
||||||
//mutex_unlock(&uevent_sock_mutex);
|
|
||||||
|
|
||||||
#[cfg(feature = "UEVENT_HELPER")]
|
|
||||||
fn handle_uevent_helper() {
|
|
||||||
// TODO
|
|
||||||
// 在特性 `UEVENT_HELPER` 开启的情况下,这里的代码会执行
|
|
||||||
// 指定处理uevent的用户空间程序,通常是热插拔程序mdev、udevd等
|
|
||||||
// /* call uevent_helper, usually only enabled during early boot */
|
|
||||||
// if (uevent_helper[0] && !kobj_usermode_filter(kobj)) {
|
|
||||||
// struct subprocess_info *info;
|
|
||||||
|
|
||||||
// retval = add_uevent_var(env, "HOME=/");
|
|
||||||
// if (retval)
|
|
||||||
// goto exit;
|
|
||||||
// retval = add_uevent_var(env,
|
|
||||||
// "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
|
|
||||||
// if (retval)
|
|
||||||
// goto exit;
|
|
||||||
// retval = init_uevent_argv(env, subsystem);
|
|
||||||
// if (retval)
|
|
||||||
// goto exit;
|
|
||||||
|
|
||||||
// retval = -ENOMEM;
|
|
||||||
// info = call_usermodehelper_setup(env->argv[0], env->argv,
|
|
||||||
// env->envp, GFP_KERNEL,
|
|
||||||
// NULL, cleanup_uevent_env, env);
|
|
||||||
// if (info) {
|
|
||||||
// retval = call_usermodehelper_exec(info, UMH_NO_WAIT);
|
|
||||||
// env = NULL; /* freed by cleanup_uevent_env */
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
#[cfg(not(feature = "UEVENT_HELPER"))]
|
|
||||||
fn handle_uevent_helper() {
|
|
||||||
// 在特性 `UEVENT_HELPER` 关闭的情况下,这里的代码会执行
|
|
||||||
}
|
|
||||||
handle_uevent_helper();
|
|
||||||
drop(devpath);
|
|
||||||
drop(env);
|
|
||||||
log::info!("kobject_uevent_env: retval: {}", retval);
|
|
||||||
return Ok(retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 以格式化字符的形式,将环境变量copy到env指针中。
|
|
||||||
pub fn add_uevent_var(
|
|
||||||
env: &mut Box<KobjUeventEnv>,
|
|
||||||
format: &str,
|
|
||||||
args: &str,
|
|
||||||
) -> Result<i32, SystemError> {
|
|
||||||
log::info!("add_uevent_var: format: {}, args: {}", format, args);
|
|
||||||
if env.envp_idx >= env.envp.capacity() {
|
|
||||||
log::info!("add_uevent_var: too many keys");
|
|
||||||
return Err(SystemError::ENOMEM);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut buffer = String::new();
|
|
||||||
write!(&mut buffer, "{} {}", format, args).map_err(|_| SystemError::ENOMEM)?;
|
|
||||||
let len = buffer.len();
|
|
||||||
|
|
||||||
if len >= env.buf.capacity() - env.buflen {
|
|
||||||
log::info!("add_uevent_var: buffer size too small");
|
|
||||||
return Err(SystemError::ENOMEM);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert the buffer to bytes and add to env.buf
|
|
||||||
env.buf.extend_from_slice(buffer.as_bytes());
|
|
||||||
env.buf.push(0); // Null-terminate the string
|
|
||||||
env.buflen += len + 1;
|
|
||||||
|
|
||||||
// Add the string to envp
|
|
||||||
env.envp.push(buffer);
|
|
||||||
env.envp_idx += 1;
|
|
||||||
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 用于处理设备树中与模块相关的环境变量
|
|
||||||
fn zap_modalias_env(env: &mut Box<KobjUeventEnv>) {
|
|
||||||
// 定义一个静态字符串
|
|
||||||
const MODALIAS_PREFIX: &str = "MODALIAS=";
|
|
||||||
let mut len: usize;
|
|
||||||
|
|
||||||
let mut i = 0;
|
|
||||||
while i < env.envp_idx {
|
|
||||||
// 如果是以 MODALIAS= 开头的字符串
|
|
||||||
if env.envp[i].starts_with(MODALIAS_PREFIX) {
|
|
||||||
len = env.envp[i].len() + 1;
|
|
||||||
// 如果不是最后一个元素
|
|
||||||
if i != env.envp_idx - 1 {
|
|
||||||
// 将后续的环境变量向前移动,以覆盖掉 "MODALIAS=" 前缀的环境变量
|
|
||||||
for j in i..env.envp_idx - 1 {
|
|
||||||
env.envp[j] = env.envp[j + 1].clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 减少环境变量数组的索引,因为一个变量已经被移除
|
|
||||||
env.envp_idx -= 1;
|
|
||||||
// 减少环境变量的总长度
|
|
||||||
env.buflen -= len;
|
|
||||||
} else {
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 用于处理网络相关的uevent(通用事件)广播
|
|
||||||
// https://code.dragonos.org.cn/xref/linux-6.1.9/lib/kobject_uevent.c#381
|
|
||||||
pub fn kobject_uevent_net_broadcast(
|
|
||||||
kobj: Arc<dyn KObject>,
|
|
||||||
env: &KobjUeventEnv,
|
|
||||||
action_string: &str,
|
|
||||||
devpath: &str,
|
|
||||||
) -> i32 {
|
|
||||||
// let net:Net = None;
|
|
||||||
// let mut ops = kobj_ns_ops(kobj);
|
|
||||||
|
|
||||||
// if (!ops && kobj.kset().is_some()) {
|
|
||||||
// let ksobj:KObject = &kobj.kset().kobj();
|
|
||||||
|
|
||||||
// if (ksobj.parent() != NULL){
|
|
||||||
// ops = kobj_ns_ops(ksobj.parent());
|
|
||||||
// }
|
|
||||||
|
|
||||||
// }
|
|
||||||
// TODO: net结构体?
|
|
||||||
// https://code.dragonos.org.cn/xref/linux-6.1.9/include/net/net_namespace.h#60
|
|
||||||
/* kobjects currently only carry network namespace tags and they
|
|
||||||
* are the only tag relevant here since we want to decide which
|
|
||||||
* network namespaces to broadcast the uevent into.
|
|
||||||
*/
|
|
||||||
// if (ops && ops.netlink_ns() && kobj.ktype().namespace())
|
|
||||||
// if (ops.type() == KOBJ_NS_TYPE_NET)
|
|
||||||
// net = kobj.ktype().namespace(kobj);
|
|
||||||
// 如果有网络命名空间,则广播标记的uevent;如果没有,则广播未标记的uevent
|
|
||||||
// if !net.is_none() {
|
|
||||||
// ret = uevent_net_broadcast_tagged(net.unwrap(), env, action_string, devpath);
|
|
||||||
// } else {
|
|
||||||
let ret = uevent_net_broadcast_untagged(env, action_string, devpath);
|
|
||||||
// }
|
|
||||||
log::info!("kobject_uevent_net_broadcast finish. ret: {}", ret);
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn uevent_net_broadcast_tagged(
|
|
||||||
sk: &dyn NetlinkSocket,
|
|
||||||
env: &KobjUeventEnv,
|
|
||||||
action_string: &str,
|
|
||||||
devpath: &str,
|
|
||||||
) -> i32 {
|
|
||||||
let ret = 0;
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 分配一个用于 uevent 消息的 skb(socket buffer)。
|
|
||||||
pub fn alloc_uevent_skb<'a>(
|
|
||||||
env: &'a KobjUeventEnv,
|
|
||||||
action_string: &'a str,
|
|
||||||
devpath: &'a str,
|
|
||||||
) -> Arc<RwLock<SkBuff>> {
|
|
||||||
let skb = Arc::new(RwLock::new(SkBuff::new()));
|
|
||||||
skb
|
|
||||||
}
|
|
||||||
// https://code.dragonos.org.cn/xref/linux-6.1.9/lib/kobject_uevent.c#309
|
|
||||||
/// 广播一个未标记的 uevent 消息
|
|
||||||
pub fn uevent_net_broadcast_untagged(
|
|
||||||
env: &KobjUeventEnv,
|
|
||||||
action_string: &str,
|
|
||||||
devpath: &str,
|
|
||||||
) -> i32 {
|
|
||||||
log::info!(
|
|
||||||
"uevent_net_broadcast_untagged: action_string: {}, devpath: {}",
|
|
||||||
action_string,
|
|
||||||
devpath
|
|
||||||
);
|
|
||||||
let mut retval = 0;
|
|
||||||
let mut skb = Arc::new(RwLock::new(SkBuff::new()));
|
|
||||||
|
|
||||||
// 锁定 UEVENT_SOCK_LIST 并遍历
|
|
||||||
let ue_sk_list = UEVENT_SOCK_LIST.lock();
|
|
||||||
for ue_sk in ue_sk_list.iter() {
|
|
||||||
// 如果没有监听者,则跳过
|
|
||||||
if netlink_has_listeners(&ue_sk.inner, 1) == 0 {
|
|
||||||
log::info!("uevent_net_broadcast_untagged: no listeners");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// 如果 skb 为空,则分配一个新的 skb
|
|
||||||
if skb.read().is_empty() {
|
|
||||||
log::info!("uevent_net_broadcast_untagged: alloc_uevent_skb failed");
|
|
||||||
retval = SystemError::ENOMEM.to_posix_errno();
|
|
||||||
skb = alloc_uevent_skb(env, action_string, devpath);
|
|
||||||
if skb.read().is_empty() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log::info!("next is netlink_broadcast");
|
|
||||||
let netlink_socket: Arc<dyn NetlinkSocket> = Arc::new(ue_sk.inner.clone());
|
|
||||||
retval = match netlink_broadcast(&netlink_socket, Arc::clone(&skb), 0, 1, 1) {
|
|
||||||
Ok(_) => 0,
|
|
||||||
Err(err) => err.to_posix_errno(),
|
|
||||||
};
|
|
||||||
log::info!("finished netlink_broadcast");
|
|
||||||
// ENOBUFS should be handled in userspace
|
|
||||||
if retval == SystemError::ENOBUFS.to_posix_errno()
|
|
||||||
|| retval == SystemError::ESRCH.to_posix_errno()
|
|
||||||
{
|
|
||||||
retval = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// consume_skb(skb);
|
|
||||||
retval
|
|
||||||
}
|
|
@ -1,239 +0,0 @@
|
|||||||
use crate::driver::base::uevent::kobject_uevent::kobject_uevent_env;
|
|
||||||
use core::fmt::Write;
|
|
||||||
/*
|
|
||||||
Struct
|
|
||||||
kset_uevent_ops
|
|
||||||
|
|
||||||
Function
|
|
||||||
|
|
||||||
get_ktype
|
|
||||||
kobject_name
|
|
||||||
kset_get
|
|
||||||
kset_put
|
|
||||||
to_kset
|
|
||||||
*/
|
|
||||||
use crate::driver::base::kobject::KObject;
|
|
||||||
use crate::driver::net::Iface;
|
|
||||||
use crate::filesystem::sysfs::{Attribute, SysFSOpsSupport, SYSFS_ATTR_MODE_RW};
|
|
||||||
use alloc::string::{String, ToString};
|
|
||||||
use alloc::sync::Arc;
|
|
||||||
use alloc::vec::Vec;
|
|
||||||
use intertrait::cast::CastArc;
|
|
||||||
use log::warn;
|
|
||||||
use system_error::SystemError;
|
|
||||||
|
|
||||||
use super::block::block_device::{BlockDevice, BlockDeviceOps};
|
|
||||||
use super::char::CharDevice;
|
|
||||||
use super::device::{Device, DeviceType};
|
|
||||||
|
|
||||||
pub mod kobject_uevent;
|
|
||||||
|
|
||||||
// https://code.dragonos.org.cn/xref/linux-6.1.9/lib/kobject_uevent.c?fi=kobject_uevent#457
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum KobjectAction {
|
|
||||||
KOBJADD,
|
|
||||||
KOBJREMOVE, // Kobject(或上层数据结构)的添加/移除事件
|
|
||||||
KOBJCHANGE, // Kobject(或上层数据结构)的状态或者内容发生改变; 如果设备驱动需要上报的事件不再上面事件的范围内,或者是自定义的事件,可以使用该event,并携带相应的参数。
|
|
||||||
KOBJMOVE, // Kobject(或上层数据结构)更改名称或者更改Parent(意味着在sysfs中更改了目录结构)
|
|
||||||
KOBJONLINE,
|
|
||||||
KOBJOFFLINE, // Kobject(或上层数据结构)的上线/下线事件,其实是是否使能
|
|
||||||
KOBJBIND,
|
|
||||||
KOBJUNBIND,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 解析一个字符串,以确定它代表的是哪个 kobject_action,并提取出随后的参数(如果有的话)
|
|
||||||
fn kobject_action_type(buf: &[u8]) -> Result<(KobjectAction, Vec<String>), SystemError> {
|
|
||||||
let mut action = KobjectAction::KOBJCHANGE;
|
|
||||||
let mut action_args: Vec<String> = Vec::new();
|
|
||||||
let mut count = buf.len();
|
|
||||||
if count != 0 && (buf[count - 1] == b'\n' || buf[count - 1] == b'\0') {
|
|
||||||
count -= 1;
|
|
||||||
}
|
|
||||||
if count == 0 {
|
|
||||||
return Err(SystemError::EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
let arg_start = buf.iter().position(|&c| c == b' ').unwrap_or(count);
|
|
||||||
let count_first = arg_start;
|
|
||||||
let args_start = arg_start + 1;
|
|
||||||
|
|
||||||
// 匹配KobjectAction
|
|
||||||
match &buf[..count_first] {
|
|
||||||
b"add" => action = KobjectAction::KOBJADD,
|
|
||||||
b"remove" => action = KobjectAction::KOBJREMOVE,
|
|
||||||
b"change" => action = KobjectAction::KOBJCHANGE,
|
|
||||||
b"move" => action = KobjectAction::KOBJMOVE,
|
|
||||||
b"online" => action = KobjectAction::KOBJONLINE,
|
|
||||||
b"offline" => action = KobjectAction::KOBJOFFLINE,
|
|
||||||
b"bind" => action = KobjectAction::KOBJBIND,
|
|
||||||
b"unbind" => action = KobjectAction::KOBJUNBIND,
|
|
||||||
_ => return Err(SystemError::EINVAL),
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果有参数,提取参数
|
|
||||||
if count - args_start > 0 {
|
|
||||||
action_args = buf[args_start..]
|
|
||||||
.split(|&c| c == b' ')
|
|
||||||
.map(|s| String::from_utf8_lossy(s).to_string())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok((action, action_args))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const UEVENT_NUM_ENVP: usize = 64;
|
|
||||||
pub const UEVENT_BUFFER_SIZE: usize = 2048;
|
|
||||||
pub const UEVENT_HELPER_PATH_LEN: usize = 256;
|
|
||||||
|
|
||||||
/// 表示处理内核对象 uevents 的环境
|
|
||||||
/// - envp,指针数组,用于保存每个环境变量的地址,最多可支持的环境变量数量为UEVENT_NUM_ENVP。
|
|
||||||
/// - envp_idx,用于访问环境变量指针数组的index。
|
|
||||||
/// - buf,保存环境变量的buffer,最大为UEVENT_BUFFER_SIZE。
|
|
||||||
/// - buflen,访问buf的变量。
|
|
||||||
// https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/kobject.h#31
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct KobjUeventEnv {
|
|
||||||
argv: Vec<String>,
|
|
||||||
envp: Vec<String>,
|
|
||||||
envp_idx: usize,
|
|
||||||
buf: Vec<u8>,
|
|
||||||
buflen: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
// kset_uevent_ops是为kset量身订做的一个数据结构,里面包含filter和uevent两个回调函数,用处如下:
|
|
||||||
/*
|
|
||||||
filter,当任何Kobject需要上报uevent时,它所属的kset可以通过该接口过滤,阻止不希望上报的event,从而达到从整体上管理的目的。
|
|
||||||
|
|
||||||
name,该接口可以返回kset的名称。如果一个kset没有合法的名称,则其下的所有Kobject将不允许上报uvent
|
|
||||||
|
|
||||||
uevent,当任何Kobject需要上报uevent时,它所属的kset可以通过该接口统一为这些event添加环境变量。因为很多时候上报uevent时的环境变量都是相同的,因此可以由kset统一处理,就不需要让每个Kobject独自添加了。
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
/// 设备文件夹下的`uevent`文件的属性
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct UeventAttr;
|
|
||||||
|
|
||||||
impl Attribute for UeventAttr {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"uevent"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mode(&self) -> crate::filesystem::vfs::syscall::ModeType {
|
|
||||||
SYSFS_ATTR_MODE_RW
|
|
||||||
}
|
|
||||||
|
|
||||||
fn support(&self) -> crate::filesystem::sysfs::SysFSOpsSupport {
|
|
||||||
SysFSOpsSupport::ATTR_SHOW | SysFSOpsSupport::ATTR_STORE
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 用户空间读取 uevent 文件,返回 uevent 信息
|
|
||||||
fn show(&self, _kobj: Arc<dyn KObject>, _buf: &mut [u8]) -> Result<usize, SystemError> {
|
|
||||||
let device = _kobj.cast::<dyn Device>().map_err(|e: Arc<dyn KObject>| {
|
|
||||||
warn!("device:{:?} is not a device!", e);
|
|
||||||
SystemError::EINVAL
|
|
||||||
})?;
|
|
||||||
log::info!("show uevent");
|
|
||||||
let device_type = device.dev_type();
|
|
||||||
let mut uevent_content = String::new();
|
|
||||||
log::info!("device_type: {:?}", device_type);
|
|
||||||
match device_type {
|
|
||||||
DeviceType::Block => {
|
|
||||||
let major = device.id_table().device_number().major().data();
|
|
||||||
let minor = device.id_table().device_number().minor();
|
|
||||||
let device_name = device.id_table().name();
|
|
||||||
writeln!(&mut uevent_content, "MAJOR={:?}", major).unwrap();
|
|
||||||
writeln!(&mut uevent_content, "MINOR={:?}", minor).unwrap();
|
|
||||||
writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap();
|
|
||||||
writeln!(&mut uevent_content, "DEVTYPE=disk").unwrap();
|
|
||||||
}
|
|
||||||
DeviceType::Char => {
|
|
||||||
let major = device.id_table().device_number().major().data();
|
|
||||||
let minor = device.id_table().device_number().minor();
|
|
||||||
let device_name = device.id_table().name();
|
|
||||||
writeln!(&mut uevent_content, "MAJOR={}", major).unwrap();
|
|
||||||
writeln!(&mut uevent_content, "MINOR={}", minor).unwrap();
|
|
||||||
writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap();
|
|
||||||
writeln!(&mut uevent_content, "DEVTYPE=char").unwrap();
|
|
||||||
}
|
|
||||||
DeviceType::Net => {
|
|
||||||
let net_device =
|
|
||||||
device
|
|
||||||
.clone()
|
|
||||||
.cast::<dyn Iface>()
|
|
||||||
.map_err(|e: Arc<dyn Device>| {
|
|
||||||
warn!("device:{:?} is not a net device!", e);
|
|
||||||
SystemError::EINVAL
|
|
||||||
})?;
|
|
||||||
let iface_id = net_device.nic_id();
|
|
||||||
let device_name = device.name();
|
|
||||||
writeln!(&mut uevent_content, "INTERFACE={}", device_name).unwrap();
|
|
||||||
writeln!(&mut uevent_content, "IFINDEX={}", iface_id).unwrap();
|
|
||||||
}
|
|
||||||
DeviceType::Bus => {
|
|
||||||
// 处理总线设备类型
|
|
||||||
let device_name = device.name();
|
|
||||||
writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap();
|
|
||||||
writeln!(&mut uevent_content, "DEVTYPE=bus").unwrap();
|
|
||||||
}
|
|
||||||
DeviceType::Rtc => {
|
|
||||||
// 处理RTC设备类型
|
|
||||||
let device_name = device.name();
|
|
||||||
writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap();
|
|
||||||
writeln!(&mut uevent_content, "DEVTYPE=rtc").unwrap();
|
|
||||||
}
|
|
||||||
DeviceType::Pci => {
|
|
||||||
// 处理PCI设备类型
|
|
||||||
let device_name = device.name();
|
|
||||||
writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap();
|
|
||||||
writeln!(&mut uevent_content, "DEVTYPE=pci").unwrap();
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// 处理其他设备类型
|
|
||||||
let device_name = device.name();
|
|
||||||
writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap();
|
|
||||||
writeln!(&mut uevent_content, "DEVTYPE={:?}", device_type).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sysfs_emit_str(_buf, &uevent_content)
|
|
||||||
}
|
|
||||||
/// 捕获来自用户空间对 uevent 文件的写操作,触发uevent事件
|
|
||||||
fn store(&self, _kobj: Arc<dyn KObject>, _buf: &[u8]) -> Result<usize, SystemError> {
|
|
||||||
log::info!("store uevent");
|
|
||||||
return kobject_synth_uevent(_buf, _kobj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 将设备的基本信息写入 uevent 文件
|
|
||||||
fn sysfs_emit_str(buf: &mut [u8], content: &str) -> Result<usize, SystemError> {
|
|
||||||
log::info!("sysfs_emit_str");
|
|
||||||
let bytes = content.as_bytes();
|
|
||||||
if buf.len() < bytes.len() {
|
|
||||||
return Err(SystemError::ENOMEM);
|
|
||||||
}
|
|
||||||
buf[..bytes.len()].copy_from_slice(bytes);
|
|
||||||
Ok(bytes.len())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 解析用户空间写入的 uevent 信息,触发 uevent 事件
|
|
||||||
fn kobject_synth_uevent(buf: &[u8], kobj: Arc<dyn KObject>) -> Result<usize, SystemError> {
|
|
||||||
let no_uuid_envp = vec!["SYNTH_UUID=0".to_string()];
|
|
||||||
let (action, action_args) = kobject_action_type(buf)?;
|
|
||||||
|
|
||||||
let result = if action_args.is_empty() {
|
|
||||||
kobject_uevent_env(kobj.clone(), action, no_uuid_envp)
|
|
||||||
} else {
|
|
||||||
kobject_uevent_env(kobj.clone(), action, action_args)
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(e) = result {
|
|
||||||
let device = kobj.cast::<dyn Device>().map_err(|e: Arc<dyn KObject>| {
|
|
||||||
warn!("device:{:?} is not a device!", e);
|
|
||||||
SystemError::EINVAL
|
|
||||||
})?;
|
|
||||||
let devname = device.name();
|
|
||||||
log::error!("synth uevent: {}: {:?}", devname, e);
|
|
||||||
return Err(SystemError::EINVAL);
|
|
||||||
}
|
|
||||||
Ok(buf.len())
|
|
||||||
}
|
|
@ -24,7 +24,7 @@ use crate::{
|
|||||||
device::{
|
device::{
|
||||||
bus::Bus,
|
bus::Bus,
|
||||||
driver::{Driver, DriverCommonData},
|
driver::{Driver, DriverCommonData},
|
||||||
CommonAttrGroup, Device, DeviceCommonData, DeviceId, DeviceType, IdTable,
|
Device, DeviceCommonData, DeviceId, DeviceType, IdTable,
|
||||||
},
|
},
|
||||||
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
||||||
kset::KSet,
|
kset::KSet,
|
||||||
@ -409,7 +409,7 @@ impl Device for VirtIOBlkDevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
||||||
Some(&[&CommonAttrGroup])
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
driver::base::{
|
driver::base::{
|
||||||
class::{class_manager, Class},
|
class::{class_manager, Class},
|
||||||
device::{sys_dev_char_kset, CommonAttrGroup},
|
device::sys_dev_char_kset,
|
||||||
kobject::KObject,
|
kobject::KObject,
|
||||||
subsys::SubSysPrivate,
|
subsys::SubSysPrivate,
|
||||||
},
|
},
|
||||||
@ -78,6 +78,6 @@ impl Class for NetClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn dev_groups(&self) -> &'static [&'static dyn AttributeGroup] {
|
fn dev_groups(&self) -> &'static [&'static dyn AttributeGroup] {
|
||||||
return &[&NetAttrGroup, &CommonAttrGroup];
|
return &[&NetAttrGroup];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ use crate::{
|
|||||||
device::{
|
device::{
|
||||||
bus::Bus,
|
bus::Bus,
|
||||||
driver::{Driver, DriverCommonData},
|
driver::{Driver, DriverCommonData},
|
||||||
CommonAttrGroup, Device, DeviceCommonData, DeviceId, DeviceType, IdTable,
|
Device, DeviceCommonData, DeviceId, DeviceType, IdTable,
|
||||||
},
|
},
|
||||||
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
||||||
kset::KSet,
|
kset::KSet,
|
||||||
@ -251,7 +251,7 @@ impl Device for VirtIONetDevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
||||||
Some(&[&CommonAttrGroup])
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,10 +8,7 @@ use alloc::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
driver::base::{
|
driver::base::{
|
||||||
class::Class,
|
class::Class,
|
||||||
device::{
|
device::{bus::Bus, driver::Driver, Device, DeviceCommonData, DeviceType, IdTable},
|
||||||
bus::Bus, driver::Driver, CommonAttrGroup, Device, DeviceCommonData, DeviceType,
|
|
||||||
IdTable,
|
|
||||||
},
|
|
||||||
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
||||||
kset::KSet,
|
kset::KSet,
|
||||||
},
|
},
|
||||||
@ -87,7 +84,7 @@ impl PciDevice for PciGeneralDevice {
|
|||||||
|
|
||||||
impl Device for PciGeneralDevice {
|
impl Device for PciGeneralDevice {
|
||||||
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
||||||
Some(&[&BasicPciReadOnlyAttrs, &CommonAttrGroup])
|
Some(&[&BasicPciReadOnlyAttrs])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bus(&self) -> Option<Weak<dyn Bus>> {
|
fn bus(&self) -> Option<Weak<dyn Bus>> {
|
||||||
|
@ -10,10 +10,7 @@ use crate::{
|
|||||||
driver::{
|
driver::{
|
||||||
base::{
|
base::{
|
||||||
class::Class,
|
class::Class,
|
||||||
device::{
|
device::{bus::Bus, driver::Driver, Device, DeviceCommonData, DeviceType, IdTable},
|
||||||
bus::Bus, driver::Driver, CommonAttrGroup, Device, DeviceCommonData, DeviceType,
|
|
||||||
IdTable,
|
|
||||||
},
|
|
||||||
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
||||||
kset::KSet,
|
kset::KSet,
|
||||||
},
|
},
|
||||||
@ -77,7 +74,7 @@ impl PciDevice for TestDevice {
|
|||||||
|
|
||||||
impl Device for TestDevice {
|
impl Device for TestDevice {
|
||||||
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
||||||
Some(&[&HelloAttr, &CommonAttrGroup])
|
Some(&[&HelloAttr])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bus(&self) -> Option<Weak<dyn Bus>> {
|
fn bus(&self) -> Option<Weak<dyn Bus>> {
|
||||||
|
@ -9,7 +9,7 @@ use unified_init::macros::unified_init;
|
|||||||
use crate::{
|
use crate::{
|
||||||
driver::base::{
|
driver::base::{
|
||||||
class::{class_manager, Class},
|
class::{class_manager, Class},
|
||||||
device::{device_manager, sys_dev_char_kset, CommonAttrGroup},
|
device::{device_manager, sys_dev_char_kset},
|
||||||
kobject::KObject,
|
kobject::KObject,
|
||||||
subsys::SubSysPrivate,
|
subsys::SubSysPrivate,
|
||||||
},
|
},
|
||||||
@ -80,7 +80,7 @@ impl Class for RtcClass {
|
|||||||
return &self.subsystem;
|
return &self.subsystem;
|
||||||
}
|
}
|
||||||
fn dev_groups(&self) -> &'static [&'static dyn AttributeGroup] {
|
fn dev_groups(&self) -> &'static [&'static dyn AttributeGroup] {
|
||||||
return &[&CommonAttrGroup];
|
return &[];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,8 +9,7 @@ use crate::{
|
|||||||
driver::base::{
|
driver::base::{
|
||||||
class::Class,
|
class::Class,
|
||||||
device::{
|
device::{
|
||||||
bus::Bus, device_manager, driver::Driver, CommonAttrGroup, Device, DeviceCommonData,
|
bus::Bus, device_manager, driver::Driver, Device, DeviceCommonData, DeviceType, IdTable,
|
||||||
DeviceType, IdTable,
|
|
||||||
},
|
},
|
||||||
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
||||||
kset::KSet,
|
kset::KSet,
|
||||||
@ -173,7 +172,7 @@ impl Device for RtcGeneralDevice {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
||||||
Some(&[&RtcAttrGroup, &CommonAttrGroup])
|
Some(&[&RtcAttrGroup])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dev_parent(&self) -> Option<Weak<dyn Device>> {
|
fn dev_parent(&self) -> Option<Weak<dyn Device>> {
|
||||||
|
@ -8,11 +8,10 @@ use unified_init::macros::unified_init;
|
|||||||
use crate::{
|
use crate::{
|
||||||
driver::base::{
|
driver::base::{
|
||||||
class::{class_manager, Class},
|
class::{class_manager, Class},
|
||||||
device::{sys_dev_char_kset, CommonAttrGroup},
|
device::sys_dev_char_kset,
|
||||||
kobject::KObject,
|
kobject::KObject,
|
||||||
subsys::SubSysPrivate,
|
subsys::SubSysPrivate,
|
||||||
},
|
},
|
||||||
filesystem::sysfs::AttributeGroup,
|
|
||||||
init::initcall::INITCALL_SUBSYS,
|
init::initcall::INITCALL_SUBSYS,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -62,10 +61,6 @@ impl Class for TtyClass {
|
|||||||
fn subsystem(&self) -> &SubSysPrivate {
|
fn subsystem(&self) -> &SubSysPrivate {
|
||||||
return &self.subsystem;
|
return &self.subsystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dev_groups(&self) -> &'static [&'static dyn AttributeGroup] {
|
|
||||||
return &[&CommonAttrGroup];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 初始化帧缓冲区子系统
|
/// 初始化帧缓冲区子系统
|
||||||
|
@ -11,8 +11,8 @@ use crate::{
|
|||||||
base::{
|
base::{
|
||||||
class::Class,
|
class::Class,
|
||||||
device::{
|
device::{
|
||||||
bus::Bus, device_manager, driver::Driver, CommonAttrGroup, Device,
|
bus::Bus, device_manager, driver::Driver, Device, DeviceCommonData, DeviceType,
|
||||||
DeviceCommonData, DeviceType, IdTable,
|
IdTable,
|
||||||
},
|
},
|
||||||
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
||||||
kset::KSet,
|
kset::KSet,
|
||||||
@ -235,7 +235,7 @@ impl Device for FbConsoleDevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
||||||
return Some(&[&AnonymousAttributeGroup, &CommonAttrGroup]);
|
return Some(&[&AnonymousAttributeGroup]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dev_parent(&self) -> Option<Weak<dyn Device>> {
|
fn dev_parent(&self) -> Option<Weak<dyn Device>> {
|
||||||
|
@ -18,7 +18,7 @@ use crate::{
|
|||||||
device_manager,
|
device_manager,
|
||||||
device_number::{DeviceNumber, Major},
|
device_number::{DeviceNumber, Major},
|
||||||
driver::Driver,
|
driver::Driver,
|
||||||
sys_dev_char_kset, CommonAttrGroup, Device, DeviceCommonData, DeviceType, IdTable,
|
sys_dev_char_kset, Device, DeviceCommonData, DeviceType, IdTable,
|
||||||
},
|
},
|
||||||
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
||||||
kset::KSet,
|
kset::KSet,
|
||||||
@ -114,7 +114,7 @@ impl Class for GraphicsClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn dev_groups(&self) -> &'static [&'static dyn AttributeGroup] {
|
fn dev_groups(&self) -> &'static [&'static dyn AttributeGroup] {
|
||||||
return &[&CommonAttrGroup];
|
return &[];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,7 +377,7 @@ impl Device for FbDevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
||||||
Some(&[&FbDeviceAttrGroup, &CommonAttrGroup])
|
Some(&[&FbDeviceAttrGroup])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dev_parent(&self) -> Option<Weak<dyn Device>> {
|
fn dev_parent(&self) -> Option<Weak<dyn Device>> {
|
||||||
|
@ -5,7 +5,6 @@ use unified_init::macros::unified_init;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
driver::base::{
|
driver::base::{
|
||||||
device::CommonAttrGroup,
|
|
||||||
kobject::{KObjType, KObject, KObjectManager, KObjectSysFSOps},
|
kobject::{KObjType, KObject, KObjectManager, KObjectSysFSOps},
|
||||||
kset::KSet,
|
kset::KSet,
|
||||||
},
|
},
|
||||||
@ -46,7 +45,7 @@ impl KObjType for IrqKObjType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
||||||
Some(&[&IrqAttrGroup, &CommonAttrGroup])
|
Some(&[&IrqAttrGroup])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn release(&self, _kobj: Arc<dyn KObject>) {
|
fn release(&self, _kobj: Arc<dyn KObject>) {
|
||||||
|
@ -2,7 +2,6 @@ use crate::{filesystem::vfs::InodeId, net::socket};
|
|||||||
use alloc::{string::String, sync::Arc};
|
use alloc::{string::String, sync::Arc};
|
||||||
|
|
||||||
pub use smoltcp::wire::IpEndpoint;
|
pub use smoltcp::wire::IpEndpoint;
|
||||||
pub use socket::netlink::endpoint::NetlinkEndpoint;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Endpoint {
|
pub enum Endpoint {
|
||||||
@ -14,8 +13,6 @@ pub enum Endpoint {
|
|||||||
Inode((Arc<socket::Inode>, String)),
|
Inode((Arc<socket::Inode>, String)),
|
||||||
/// Unix传递id索引和path所用的端点
|
/// Unix传递id索引和path所用的端点
|
||||||
Unixpath((InodeId, String)),
|
Unixpath((InodeId, String)),
|
||||||
/// NetLink端点
|
|
||||||
Netlink(NetlinkEndpoint),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief 链路层端点
|
/// @brief 链路层端点
|
||||||
|
@ -6,7 +6,6 @@ mod endpoint;
|
|||||||
mod family;
|
mod family;
|
||||||
pub mod inet;
|
pub mod inet;
|
||||||
mod inode;
|
mod inode;
|
||||||
pub mod netlink;
|
|
||||||
pub mod unix;
|
pub mod unix;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,9 +0,0 @@
|
|||||||
use super::skbuff::SkBuff;
|
|
||||||
use crate::libs::rwlock::RwLock;
|
|
||||||
use alloc::sync::Arc;
|
|
||||||
use core::fmt::Debug;
|
|
||||||
pub trait NetlinkCallback: Send + Sync + Debug {
|
|
||||||
/// 接收到netlink数据包时的回调函数
|
|
||||||
fn netlink_rcv(&self, skb: Arc<RwLock<SkBuff>>) -> i32;
|
|
||||||
}
|
|
||||||
struct NetlinkCallbackData {}
|
|
@ -1,10 +0,0 @@
|
|||||||
use crate::net::syscall::SockAddrNl;
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct NetlinkEndpoint {
|
|
||||||
pub addr: SockAddrNl,
|
|
||||||
}
|
|
||||||
impl NetlinkEndpoint {
|
|
||||||
pub fn new(addr: SockAddrNl) -> Self {
|
|
||||||
NetlinkEndpoint { addr }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,343 +0,0 @@
|
|||||||
pub mod af_netlink;
|
|
||||||
pub mod callback;
|
|
||||||
pub mod endpoint;
|
|
||||||
pub mod netlink_proto;
|
|
||||||
pub mod skbuff;
|
|
||||||
pub mod sock;
|
|
||||||
|
|
||||||
use super::{family, inet::datagram, Inode, Socket, Type};
|
|
||||||
use crate::driver::base::uevent::KobjUeventEnv;
|
|
||||||
use alloc::sync::Arc;
|
|
||||||
use alloc::{boxed::Box, slice, vec::Vec};
|
|
||||||
use system_error::SystemError;
|
|
||||||
|
|
||||||
// https://code.dragonos.org.cn/xref/linux-6.1.9/net/netlink/
|
|
||||||
|
|
||||||
use crate::libs::mutex::Mutex;
|
|
||||||
use core::mem;
|
|
||||||
|
|
||||||
use af_netlink::{netlink_insert, Listeners, NetlinkFlags, NetlinkSock, NetlinkSocket, NL_TABLE};
|
|
||||||
// 监听事件类型
|
|
||||||
pub const NETLINK_ADD_MEMBERSHIP: usize = 1;
|
|
||||||
pub const NETLINK_DROP_MEMBERSHIP: usize = 2;
|
|
||||||
pub const NETLINK_PKTINFO: usize = 3; // 接收包信息。如果设置了这个选项,套接字将接收包含发送者信息(如发送者的端口号和地址)的消息
|
|
||||||
// Netlink protocol family
|
|
||||||
pub const NETLINK_ROUTE: usize = 0;
|
|
||||||
pub const NETLINK_UNUSED: usize = 1;
|
|
||||||
pub const NETLINK_USERSOCK: usize = 2;
|
|
||||||
pub const NETLINK_FIREWALL: usize = 3;
|
|
||||||
pub const NETLINK_SOCK_DIAG: usize = 4;
|
|
||||||
pub const NETLINK_NFLOG: usize = 5;
|
|
||||||
pub const NETLINK_XFRM: usize = 6;
|
|
||||||
pub const NETLINK_SELINUX: usize = 7;
|
|
||||||
pub const NETLINK_ISCSI: usize = 8;
|
|
||||||
pub const NETLINK_AUDIT: usize = 9;
|
|
||||||
pub const NETLINK_FIB_LOOKUP: usize = 10;
|
|
||||||
pub const NETLINK_CONNECTOR: usize = 11;
|
|
||||||
pub const NETLINK_NETFILTER: usize = 12;
|
|
||||||
pub const NETLINK_IP6_FW: usize = 13;
|
|
||||||
pub const NETLINK_DNRTMSG: usize = 14;
|
|
||||||
// implemente uevent needed
|
|
||||||
pub const NETLINK_KOBJECT_UEVENT: usize = 15;
|
|
||||||
pub const NETLINK_GENERIC: usize = 16;
|
|
||||||
// pub const NETLINK_DM : usize = 17; // Assuming DM Events is unused, not defined
|
|
||||||
pub const NETLINK_SCSITRANSPORT: usize = 18;
|
|
||||||
pub const NETLINK_ECRYPTFS: usize = 19;
|
|
||||||
pub const NETLINK_RDMA: usize = 20;
|
|
||||||
pub const NETLINK_CRYPTO: usize = 21;
|
|
||||||
pub const NETLINK_SMC: usize = 22;
|
|
||||||
|
|
||||||
//pub const NETLINK_INET_DIAG = NETLINK_SOCK_DIAG;
|
|
||||||
pub const NETLINK_INET_DIAG: usize = 4;
|
|
||||||
|
|
||||||
pub const MAX_LINKS: usize = 32;
|
|
||||||
|
|
||||||
pub const NL_CFG_F_NONROOT_RECV: u32 = 1 << 0;
|
|
||||||
pub const NL_CFG_F_NONROOT_SEND: u32 = 1 << 1;
|
|
||||||
|
|
||||||
bitflags! {
|
|
||||||
/// 四种通用的消息类型 nlmsg_type
|
|
||||||
pub struct NLmsgType: u8 {
|
|
||||||
/* Nothing. */
|
|
||||||
const NLMSG_NOOP = 0x1;
|
|
||||||
/* Error */
|
|
||||||
const NLMSG_ERROR = 0x2;
|
|
||||||
/* End of a dump */
|
|
||||||
const NLMSG_DONE = 0x3;
|
|
||||||
/* Data lost */
|
|
||||||
const NLMSG_OVERRUN = 0x4;
|
|
||||||
}
|
|
||||||
|
|
||||||
//消息标记 nlmsg_flags
|
|
||||||
// const NLM_F_REQUEST = 1; /* It is request message. */
|
|
||||||
// const NLM_F_MULTI = 2; /* Multipart message, terminated by NLMSG_DONE */
|
|
||||||
// const NLM_F_ACK = 4; /* Reply with ack, with zero or error code */
|
|
||||||
// const NLM_F_ECHO = 8; /* Echo this request */
|
|
||||||
// const NLM_F_DUMP_INTR = 16; /* Dump was inconsistent due to sequence change */
|
|
||||||
pub struct NLmsgFlags: u16 {
|
|
||||||
/* Flags values */
|
|
||||||
const NLM_F_REQUEST = 0x01;
|
|
||||||
const NLM_F_MULTI = 0x02;
|
|
||||||
const NLM_F_ACK = 0x04;
|
|
||||||
const NLM_F_ECHO = 0x08;
|
|
||||||
const NLM_F_DUMP_INTR = 0x10;
|
|
||||||
const NLM_F_DUMP_FILTERED = 0x20;
|
|
||||||
|
|
||||||
/* Modifiers to GET request */
|
|
||||||
const NLM_F_ROOT = 0x100; /* specify tree root */
|
|
||||||
const NLM_F_MATCH = 0x200; /* return all matching */
|
|
||||||
const NLM_F_ATOMIC = 0x400; /* atomic GET */
|
|
||||||
//const NLM_F_DUMP = NLM_F_ROOT | NLM_F_MATCH;
|
|
||||||
const NLM_F_DUMP = 0x100 | 0x200;
|
|
||||||
|
|
||||||
/* Modifiers to NEW request */
|
|
||||||
const NLM_F_REPLACE = 0x100; /* Override existing */
|
|
||||||
const NLM_F_EXCL = 0x200; /* Do not touch, if it exists */
|
|
||||||
const NLM_F_CREATE = 0x400; /* Create, if it does not exist */
|
|
||||||
const NLM_F_APPEND = 0x800; /* Add to end of list */
|
|
||||||
|
|
||||||
/* Modifiers to DELETE request */
|
|
||||||
const NLM_F_NONREC = 0x100; /* Do not delete recursively */
|
|
||||||
|
|
||||||
/* Flags for ACK message */
|
|
||||||
const NLM_F_CAPPED = 0x100; /* request was capped */
|
|
||||||
const NLM_F_ACK_TLVS = 0x200; /* extended ACK TVLs were included */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 定义Netlink消息的结构体,如NLmsghdr和geNLmsghdr(拓展的netlink消息头),以及用于封包和解包消息的函数。
|
|
||||||
// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/netlink.h
|
|
||||||
/// netlink消息报头
|
|
||||||
/**
|
|
||||||
* struct NLmsghdr - fixed format metadata header of Netlink messages
|
|
||||||
* @nlmsg_len: Length of message including header
|
|
||||||
* @nlmsg_type: Message content type
|
|
||||||
* @nlmsg_flags: Additional flags
|
|
||||||
* @nlmsg_seq: Sequence number
|
|
||||||
* @nlmsg_pid: Sending process port ID
|
|
||||||
*/
|
|
||||||
pub struct NLmsghdr {
|
|
||||||
pub nlmsg_len: usize,
|
|
||||||
pub nlmsg_type: NLmsgType,
|
|
||||||
pub nlmsg_flags: NLmsgFlags,
|
|
||||||
pub nlmsg_seq: u32,
|
|
||||||
pub nlmsg_pid: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
const NLMSG_ALIGNTO: usize = 4;
|
|
||||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
|
||||||
pub enum NetlinkState {
|
|
||||||
NetlinkUnconnected = 0,
|
|
||||||
NetlinkConnected,
|
|
||||||
NETLINK_S_CONGESTED = 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn nlmsg_align(len: usize) -> usize {
|
|
||||||
(len + NLMSG_ALIGNTO - 1) & !(NLMSG_ALIGNTO - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn nlmsg_hdrlen() -> usize {
|
|
||||||
nlmsg_align(mem::size_of::<NLmsghdr>())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn nlmsg_length(len: usize) -> usize {
|
|
||||||
len + nlmsg_hdrlen()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn nlmsg_space(len: usize) -> usize {
|
|
||||||
nlmsg_align(nlmsg_length(len))
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn nlmsg_data(nlh: &NLmsghdr) -> *mut u8 {
|
|
||||||
((nlh as *const NLmsghdr) as *mut u8).add(nlmsg_length(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn nlmsg_next(nlh: *mut NLmsghdr, len: usize) -> *mut NLmsghdr {
|
|
||||||
let nlmsg_len = (*nlh).nlmsg_len;
|
|
||||||
let new_len = len - nlmsg_align(nlmsg_len);
|
|
||||||
nlh.add(nlmsg_align(nlmsg_len))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn nlmsg_ok(nlh: &NLmsghdr, len: usize) -> bool {
|
|
||||||
len >= nlmsg_hdrlen() && nlh.nlmsg_len >= nlmsg_hdrlen() && nlh.nlmsg_len <= len
|
|
||||||
}
|
|
||||||
|
|
||||||
fn nlmsg_payload(nlh: &NLmsghdr, len: usize) -> usize {
|
|
||||||
nlh.nlmsg_len - nlmsg_space(len)
|
|
||||||
}
|
|
||||||
// 定义类型别名来简化闭包类型的定义
|
|
||||||
type InputCallback = Arc<dyn FnMut() + Send + Sync>;
|
|
||||||
type BindCallback = Arc<dyn Fn(i32) -> i32 + Send + Sync>;
|
|
||||||
type UnbindCallback = Arc<dyn Fn(i32) -> i32 + Send + Sync>;
|
|
||||||
type CompareCallback = Arc<dyn Fn(&NetlinkSock) -> bool + Send + Sync>;
|
|
||||||
/// 该结构包含了内核netlink的可选参数:
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct NetlinkKernelCfg {
|
|
||||||
pub groups: u32,
|
|
||||||
pub flags: u32,
|
|
||||||
pub input: Option<InputCallback>,
|
|
||||||
pub bind: Option<BindCallback>,
|
|
||||||
pub unbind: Option<UnbindCallback>,
|
|
||||||
pub compare: Option<CompareCallback>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NetlinkKernelCfg {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
NetlinkKernelCfg {
|
|
||||||
groups: 32,
|
|
||||||
flags: 0,
|
|
||||||
input: None,
|
|
||||||
bind: None,
|
|
||||||
unbind: None,
|
|
||||||
compare: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_input<F>(&mut self, callback: F)
|
|
||||||
where
|
|
||||||
F: FnMut() + Send + Sync + 'static,
|
|
||||||
{
|
|
||||||
self.input = Some(Arc::new(callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_bind<F>(&mut self, callback: F)
|
|
||||||
where
|
|
||||||
F: Fn(i32) -> i32 + Send + Sync + 'static,
|
|
||||||
{
|
|
||||||
self.bind = Some(Arc::new(callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_unbind<F>(&mut self, callback: F)
|
|
||||||
where
|
|
||||||
F: Fn(i32) -> i32 + Send + Sync + 'static,
|
|
||||||
{
|
|
||||||
self.unbind = Some(Arc::new(callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_compare<F>(&mut self, callback: F)
|
|
||||||
where
|
|
||||||
F: Fn(&NetlinkSock) -> bool + Send + Sync + 'static,
|
|
||||||
{
|
|
||||||
self.compare = Some(Arc::new(callback));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/netlink.h#229
|
|
||||||
// netlink属性头
|
|
||||||
struct NLattr {
|
|
||||||
nla_len: u16,
|
|
||||||
nla_type: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait VecExt {
|
|
||||||
fn align4(&mut self);
|
|
||||||
fn push_ext<T: Sized>(&mut self, data: T);
|
|
||||||
fn set_ext<T: Sized>(&mut self, offset: usize, data: T);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VecExt for Vec<u8> {
|
|
||||||
fn align4(&mut self) {
|
|
||||||
let len = (self.len() + 3) & !3;
|
|
||||||
if len > self.len() {
|
|
||||||
self.resize(len, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_ext<T: Sized>(&mut self, data: T) {
|
|
||||||
#[allow(unsafe_code)]
|
|
||||||
let bytes =
|
|
||||||
unsafe { slice::from_raw_parts(&data as *const T as *const u8, size_of::<T>()) };
|
|
||||||
for byte in bytes {
|
|
||||||
self.push(*byte);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_ext<T: Sized>(&mut self, offset: usize, data: T) {
|
|
||||||
if self.len() < offset + size_of::<T>() {
|
|
||||||
self.resize(offset + size_of::<T>(), 0);
|
|
||||||
}
|
|
||||||
#[allow(unsafe_code)]
|
|
||||||
let bytes =
|
|
||||||
unsafe { slice::from_raw_parts(&data as *const T as *const u8, size_of::<T>()) };
|
|
||||||
self[offset..(bytes.len() + offset)].copy_from_slice(bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo: net namespace
|
|
||||||
pub fn netlink_kernel_create(
|
|
||||||
unit: usize,
|
|
||||||
cfg: Option<NetlinkKernelCfg>,
|
|
||||||
) -> Result<NetlinkSock, SystemError> {
|
|
||||||
// THIS_MODULE
|
|
||||||
let mut nlk: NetlinkSock = NetlinkSock::new();
|
|
||||||
let sk: Arc<Mutex<Box<dyn NetlinkSocket>>> = Arc::new(Mutex::new(Box::new(nlk.clone())));
|
|
||||||
let groups: u32;
|
|
||||||
if unit >= MAX_LINKS {
|
|
||||||
return Err(SystemError::EINVAL);
|
|
||||||
}
|
|
||||||
__netlink_create(&mut nlk, unit, 1).expect("__netlink_create failed");
|
|
||||||
|
|
||||||
if let Some(cfg) = cfg.as_ref() {
|
|
||||||
if cfg.groups < 32 {
|
|
||||||
groups = 32;
|
|
||||||
} else {
|
|
||||||
groups = cfg.groups;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
groups = 32;
|
|
||||||
}
|
|
||||||
let listeners = Listeners::new();
|
|
||||||
// todo:设计和实现回调函数
|
|
||||||
// sk.sk_data_read = netlink_data_ready;
|
|
||||||
// if cfg.is_some() && cfg.unwrap().input.is_some(){
|
|
||||||
// nlk.netlink_rcv = cfg.unwrap().input;
|
|
||||||
// }
|
|
||||||
netlink_insert(sk, 0).expect("netlink_insert failed");
|
|
||||||
nlk.flags |= NetlinkFlags::NETLINK_F_KERNEL_SOCKET.bits();
|
|
||||||
|
|
||||||
let mut nl_table = NL_TABLE.write();
|
|
||||||
if nl_table[unit].get_registered() == 0 {
|
|
||||||
nl_table[unit].set_groups(groups);
|
|
||||||
if let Some(cfg) = cfg.as_ref() {
|
|
||||||
nl_table[unit].bind = cfg.bind.clone();
|
|
||||||
nl_table[unit].unbind = cfg.unbind.clone();
|
|
||||||
nl_table[unit].set_flags(cfg.flags);
|
|
||||||
if cfg.compare.is_some() {
|
|
||||||
nl_table[unit].compare = cfg.compare.clone();
|
|
||||||
}
|
|
||||||
nl_table[unit].set_registered(1);
|
|
||||||
} else {
|
|
||||||
drop(listeners);
|
|
||||||
let registered = nl_table[unit].get_registered();
|
|
||||||
nl_table[unit].set_registered(registered + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Ok(nlk);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn __netlink_create(nlk: &mut NetlinkSock, unit: usize, kern: usize) -> Result<i32, SystemError> {
|
|
||||||
// 其他的初始化配置参数
|
|
||||||
nlk.flags = kern as u32;
|
|
||||||
nlk.protocol = unit;
|
|
||||||
return Ok(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sk_data_ready(nlk: Arc<NetlinkSock>) -> Result<(), SystemError> {
|
|
||||||
// 唤醒
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Netlink;
|
|
||||||
|
|
||||||
impl family::Family for Netlink {
|
|
||||||
/// 用户空间创建一个新的套接字的入口
|
|
||||||
fn socket(stype: Type, _protocol: u32) -> Result<Arc<Inode>, SystemError> {
|
|
||||||
let socket = create_netlink_socket(_protocol)?;
|
|
||||||
Ok(Inode::new(socket))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// 用户空间创建一个新的Netlink套接字
|
|
||||||
fn create_netlink_socket(_protocol: u32) -> Result<Arc<dyn Socket>, SystemError> {
|
|
||||||
match _protocol as usize {
|
|
||||||
NETLINK_KOBJECT_UEVENT => Ok(Arc::new(af_netlink::NetlinkSock::new())),
|
|
||||||
_ => Err(SystemError::EPROTONOSUPPORT),
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,56 +0,0 @@
|
|||||||
use bitmap::{traits::BitMapOps, AllocBitmap};
|
|
||||||
use core::intrinsics::unlikely;
|
|
||||||
use system_error::SystemError;
|
|
||||||
|
|
||||||
use crate::libs::lazy_init::Lazy;
|
|
||||||
pub const PROTO_INUSE_NR: usize = 64;
|
|
||||||
// pub static mut PROTO_INUSE_IDX: Lazy<AllocBitmap> = Lazy::new();
|
|
||||||
// pub static PROTO_INUSE_IDX: Lazy<AllocBitmap> = Lazy::new(<AllocBitmap::new(PROTO_INUSE_NR));
|
|
||||||
/// 协议操作集的trait
|
|
||||||
pub trait Protocol {
|
|
||||||
fn close(&self);
|
|
||||||
// fn first_false_index(&self, proto_inuse_idx:usize, proto_inuse_nr:usize)->usize;
|
|
||||||
}
|
|
||||||
/// 协议操作集的结构体
|
|
||||||
pub struct Proto<'a> {
|
|
||||||
name: &'a str,
|
|
||||||
// owner: THIS_MODULE,
|
|
||||||
obj_size: usize,
|
|
||||||
inuse_idx: Option<usize>,
|
|
||||||
}
|
|
||||||
impl Protocol for Proto<'_> {
|
|
||||||
fn close(&self) {}
|
|
||||||
}
|
|
||||||
/// 静态变量,用于注册netlink协议,是一个操作集结构体的实例
|
|
||||||
// https://code.dragonos.org.cn/xref/linux-6.1.9/net/netlink/af_netlink.c#634
|
|
||||||
pub static mut NETLINK_PROTO: Proto = Proto {
|
|
||||||
name: "NETLINK",
|
|
||||||
// owner: THIS_MODULE,
|
|
||||||
obj_size: core::mem::size_of::<Proto>(),
|
|
||||||
// 运行时分配的索引
|
|
||||||
inuse_idx: None,
|
|
||||||
};
|
|
||||||
// https://code.dragonos.org.cn/xref/linux-6.1.9/net/core/sock.c?fi=proto_register#3853
|
|
||||||
/// 注册协议
|
|
||||||
pub fn proto_register(proto: &mut Proto, alloc_slab: i32) -> Result<i32, SystemError> {
|
|
||||||
let mut ret = Err(SystemError::ENOBUFS);
|
|
||||||
if alloc_slab != 0 {
|
|
||||||
log::info!("TODO: netlink_proto: slab allocation not supported\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
ret = assign_proto_idx(proto);
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
// https://code.dragonos.org.cn/xref/linux-6.1.9/net/core/sock.c?fi=proto_register#3752
|
|
||||||
/// 为协议分配一个索引
|
|
||||||
pub fn assign_proto_idx(prot: &mut Proto) -> Result<i32, SystemError> {
|
|
||||||
// prot.inuse_idx = unsafe { PROTO_INUSE_IDX.first_false_index() };
|
|
||||||
// 如果没有找到空闲的索引
|
|
||||||
if unlikely(prot.inuse_idx == Some(PROTO_INUSE_NR - 1)) {
|
|
||||||
log::info!("PROTO_INUSE_NR exhausted\n");
|
|
||||||
return Err(SystemError::ENOSPC);
|
|
||||||
}
|
|
||||||
// 为协议分配一个索引
|
|
||||||
// unsafe { PROTO_INUSE_IDX.set((prot.inuse_idx).unwrap(), true) };
|
|
||||||
return Ok(0);
|
|
||||||
}
|
|
@ -1,109 +0,0 @@
|
|||||||
use super::af_netlink::{NetlinkSock, NetlinkSocket};
|
|
||||||
use crate::libs::{mutex::Mutex, rwlock::RwLock};
|
|
||||||
use alloc::{boxed::Box, sync::Arc};
|
|
||||||
// 曾用方案:在 smoltcp::PacketBuffer 的基础上封装了一层,用于处理 netlink 协议中网络数据包(skb)的相关操作
|
|
||||||
// 暂时弃用,目前尝试使用更简单的方式处理 skb
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct SkBuff {
|
|
||||||
pub sk: Arc<Mutex<Box<dyn NetlinkSocket>>>,
|
|
||||||
pub len: u32,
|
|
||||||
pub pkt_type: u32,
|
|
||||||
pub mark: u32,
|
|
||||||
pub queue_mapping: u32,
|
|
||||||
pub protocol: u32,
|
|
||||||
pub vlan_present: u32,
|
|
||||||
pub vlan_tci: u32,
|
|
||||||
pub vlan_proto: u32,
|
|
||||||
pub priority: u32,
|
|
||||||
pub ingress_ifindex: u32,
|
|
||||||
pub ifindex: u32,
|
|
||||||
pub tc_index: u32,
|
|
||||||
pub cb: [u32; 5],
|
|
||||||
pub hash: u32,
|
|
||||||
pub tc_classid: u32,
|
|
||||||
pub data: u32,
|
|
||||||
pub data_end: u32,
|
|
||||||
pub napi_id: u32,
|
|
||||||
pub family: u32,
|
|
||||||
pub remote_ip4: u32,
|
|
||||||
pub local_ip4: u32,
|
|
||||||
pub remote_ip6: [u32; 4],
|
|
||||||
pub local_ip6: [u32; 4],
|
|
||||||
pub remote_port: u32,
|
|
||||||
pub local_port: u32,
|
|
||||||
pub data_meta: u32,
|
|
||||||
pub tstamp: u64,
|
|
||||||
pub wire_len: u32,
|
|
||||||
pub gso_segs: u32,
|
|
||||||
pub gso_size: u32,
|
|
||||||
pub tstamp_type: u8,
|
|
||||||
pub _bitfield_align_1: [u8; 0],
|
|
||||||
pub hwtstamp: u64,
|
|
||||||
}
|
|
||||||
impl SkBuff {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
SkBuff {
|
|
||||||
sk: Arc::new(Mutex::new(Box::new(NetlinkSock::new()))),
|
|
||||||
len: 0,
|
|
||||||
pkt_type: 0,
|
|
||||||
mark: 0,
|
|
||||||
queue_mapping: 0,
|
|
||||||
protocol: 0,
|
|
||||||
vlan_present: 0,
|
|
||||||
vlan_tci: 0,
|
|
||||||
vlan_proto: 0,
|
|
||||||
priority: 0,
|
|
||||||
ingress_ifindex: 0,
|
|
||||||
ifindex: 0,
|
|
||||||
tc_index: 0,
|
|
||||||
cb: [0; 5],
|
|
||||||
hash: 0,
|
|
||||||
tc_classid: 0,
|
|
||||||
data: 0,
|
|
||||||
data_end: 0,
|
|
||||||
napi_id: 0,
|
|
||||||
family: 0,
|
|
||||||
remote_ip4: 0,
|
|
||||||
local_ip4: 0,
|
|
||||||
remote_ip6: [0; 4],
|
|
||||||
local_ip6: [0; 4],
|
|
||||||
remote_port: 0,
|
|
||||||
local_port: 0,
|
|
||||||
data_meta: 0,
|
|
||||||
tstamp: 0,
|
|
||||||
wire_len: 0,
|
|
||||||
gso_segs: 0,
|
|
||||||
gso_size: 0,
|
|
||||||
tstamp_type: 0,
|
|
||||||
_bitfield_align_1: [0; 0],
|
|
||||||
hwtstamp: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.len == 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理网络套接字的过度运行情况
|
|
||||||
pub fn netlink_overrun(sk: &Arc<Mutex<Box<dyn NetlinkSocket>>>) {
|
|
||||||
// Implementation of the function
|
|
||||||
}
|
|
||||||
|
|
||||||
// 用于检查网络数据包(skb)是否被共享
|
|
||||||
pub fn skb_shared(skb: &RwLock<SkBuff>) -> bool {
|
|
||||||
// Implementation of the function
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 处理被孤儿化的网络数据包(skb)
|
|
||||||
/// 孤儿化网络数据包意味着数据包不再与任何套接字关联,
|
|
||||||
/// 通常是因为发送数据包时指定了 MSG_DONTWAIT 标志,这告诉内核不要等待必要的资源(如内存),而是尽可能快地发送数据包。
|
|
||||||
pub fn skb_orphan(skb: &Arc<RwLock<SkBuff>>) {
|
|
||||||
// TODO: Implementation of the function
|
|
||||||
}
|
|
||||||
|
|
||||||
fn skb_recv_datagram() {}
|
|
||||||
|
|
||||||
fn skb_try_recv_datagram() {}
|
|
||||||
|
|
||||||
fn skb_try_recv_from_queue() {}
|
|
@ -1,33 +0,0 @@
|
|||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum SockFlags {
|
|
||||||
Dead,
|
|
||||||
Done,
|
|
||||||
Urginline,
|
|
||||||
Keepopen,
|
|
||||||
Linger,
|
|
||||||
Destroy,
|
|
||||||
Broadcast,
|
|
||||||
Timestamp,
|
|
||||||
Zapped,
|
|
||||||
UseWriteQueue, // whether to call sk->sk_write_space in _wfree
|
|
||||||
Dbg, // %SO_DEBUG setting
|
|
||||||
Rcvtstamp, // %SO_TIMESTAMP setting
|
|
||||||
Rcvtstampns, // %SO_TIMESTAMPNS setting
|
|
||||||
Localroute, // route locally only, %SO_DONTROUTE setting
|
|
||||||
Memalloc, // VM depends on this et for swapping
|
|
||||||
TimestampingRxSoftware, // %SOF_TIMESTAMPING_RX_SOFTWARE
|
|
||||||
Fasync, // fasync() active
|
|
||||||
RxqOvfl,
|
|
||||||
Zerocopy, // buffers from userspace
|
|
||||||
WifiStatus, // push wifi status to userspace
|
|
||||||
Nofcs, // Tell NIC not to do the Ethernet FCS.
|
|
||||||
// Will use last 4 bytes of packet sent from
|
|
||||||
// user-space instead.
|
|
||||||
FilterLocked, // Filter cannot be changed anymore
|
|
||||||
SelectErrQueue, // Wake select on error queue
|
|
||||||
RcuFree, // wait rcu grace period in sk_destruct()
|
|
||||||
Txtime,
|
|
||||||
Xdp, // XDP is attached
|
|
||||||
TstampNew, // Indicates 64 bit timestamps always
|
|
||||||
Rcvmark, // Receive SO_MARK ancillary data with packet
|
|
||||||
}
|
|
@ -17,7 +17,6 @@ pub fn create_socket(
|
|||||||
todo!("AF_INET6 unimplemented");
|
todo!("AF_INET6 unimplemented");
|
||||||
}
|
}
|
||||||
AF::Unix => socket::unix::Unix::socket(socket_type, protocol)?,
|
AF::Unix => socket::unix::Unix::socket(socket_type, protocol)?,
|
||||||
AF::Netlink => socket::netlink::Netlink::socket(socket_type, protocol)?,
|
|
||||||
_ => {
|
_ => {
|
||||||
todo!("unsupport address family");
|
todo!("unsupport address family");
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::socket::{self, Endpoint, Socket};
|
use super::socket::{self, Endpoint, Socket};
|
||||||
use super::socket::{netlink::endpoint, unix::Unix, AddressFamily as AF};
|
use super::socket::{unix::Unix, AddressFamily as AF};
|
||||||
|
|
||||||
pub use super::syscall_util::*;
|
pub use super::syscall_util::*;
|
||||||
|
|
||||||
|
@ -186,11 +186,6 @@ impl SockAddr {
|
|||||||
log::warn!("not support address family {:?}", addr.family);
|
log::warn!("not support address family {:?}", addr.family);
|
||||||
return Err(SystemError::EINVAL);
|
return Err(SystemError::EINVAL);
|
||||||
}
|
}
|
||||||
AddressFamily::Netlink => {
|
|
||||||
// TODO: support netlink socket
|
|
||||||
let addr: SockAddrNl = addr.addr_nl;
|
|
||||||
return Ok(Endpoint::Netlink(NetlinkEndpoint::new(addr)));
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
log::warn!("not support address family {:?}", addr.family);
|
log::warn!("not support address family {:?}", addr.family);
|
||||||
return Err(SystemError::EINVAL);
|
return Err(SystemError::EINVAL);
|
||||||
@ -290,17 +285,6 @@ impl From<Endpoint> for SockAddr {
|
|||||||
return SockAddr { addr_ll };
|
return SockAddr { addr_ll };
|
||||||
}
|
}
|
||||||
|
|
||||||
Endpoint::Netlink(netlink_endpoint) => {
|
|
||||||
let addr_nl = SockAddrNl {
|
|
||||||
nl_family: AddressFamily::Netlink,
|
|
||||||
nl_pad: 0,
|
|
||||||
nl_pid: netlink_endpoint.addr.nl_pid,
|
|
||||||
nl_groups: netlink_endpoint.addr.nl_groups,
|
|
||||||
};
|
|
||||||
|
|
||||||
return SockAddr { addr_nl };
|
|
||||||
}
|
|
||||||
|
|
||||||
Endpoint::Inode((_, path)) => {
|
Endpoint::Inode((_, path)) => {
|
||||||
log::debug!("from unix path {:?}", path);
|
log::debug!("from unix path {:?}", path);
|
||||||
let bytes = path.as_bytes();
|
let bytes = path.as_bytes();
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
[build]
|
|
||||||
target = "x86_64-unknown-linux-musl"
|
|
3
user/apps/test-uevent/.gitignore
vendored
3
user/apps/test-uevent/.gitignore
vendored
@ -1,3 +0,0 @@
|
|||||||
/target
|
|
||||||
Cargo.lock
|
|
||||||
/install/
|
|
@ -1,12 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "test-uevent"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
description = "test for uevent"
|
|
||||||
authors = [ "val213 <val213666@gmail.com>" ]
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
netlink-sys = "0.5"
|
|
||||||
nix = "0.24"
|
|
@ -1,56 +0,0 @@
|
|||||||
TOOLCHAIN="+nightly-2023-08-15-x86_64-unknown-linux-gnu"
|
|
||||||
RUSTFLAGS+=""
|
|
||||||
|
|
||||||
ifdef DADK_CURRENT_BUILD_DIR
|
|
||||||
# 如果是在dadk中编译,那么安装到dadk的安装目录中
|
|
||||||
INSTALL_DIR = $(DADK_CURRENT_BUILD_DIR)
|
|
||||||
else
|
|
||||||
# 如果是在本地编译,那么安装到当前目录下的install目录中
|
|
||||||
INSTALL_DIR = ./install
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(ARCH), x86_64)
|
|
||||||
export RUST_TARGET=x86_64-unknown-linux-musl
|
|
||||||
else ifeq ($(ARCH), riscv64)
|
|
||||||
export RUST_TARGET=riscv64gc-unknown-linux-gnu
|
|
||||||
else
|
|
||||||
# 默认为x86_86,用于本地编译
|
|
||||||
export RUST_TARGET=x86_64-unknown-linux-musl
|
|
||||||
endif
|
|
||||||
|
|
||||||
run:
|
|
||||||
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --target $(RUST_TARGET)
|
|
||||||
|
|
||||||
build:
|
|
||||||
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET)
|
|
||||||
|
|
||||||
clean:
|
|
||||||
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --target $(RUST_TARGET)
|
|
||||||
|
|
||||||
test:
|
|
||||||
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test --target $(RUST_TARGET)
|
|
||||||
|
|
||||||
doc:
|
|
||||||
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) doc --target $(RUST_TARGET)
|
|
||||||
|
|
||||||
fmt:
|
|
||||||
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt
|
|
||||||
|
|
||||||
fmt-check:
|
|
||||||
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt --check
|
|
||||||
|
|
||||||
run-release:
|
|
||||||
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --target $(RUST_TARGET) --release
|
|
||||||
|
|
||||||
build-release:
|
|
||||||
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET) --release
|
|
||||||
|
|
||||||
clean-release:
|
|
||||||
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --target $(RUST_TARGET) --release
|
|
||||||
|
|
||||||
test-release:
|
|
||||||
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test --target $(RUST_TARGET) --release
|
|
||||||
|
|
||||||
.PHONY: install
|
|
||||||
install:
|
|
||||||
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) install --target $(RUST_TARGET) --path . --no-track --root $(INSTALL_DIR) --force
|
|
@ -1,14 +0,0 @@
|
|||||||
# DragonOS Rust-Application Template
|
|
||||||
|
|
||||||
您可以使用此模板来创建DragonOS应用程序。
|
|
||||||
|
|
||||||
## 使用方法
|
|
||||||
|
|
||||||
1. 使用DragonOS的tools目录下的`bootstrap.sh`脚本初始化环境
|
|
||||||
2. 在终端输入`cargo install cargo-generate`
|
|
||||||
3. 在终端输入`cargo generate --git https://github.com/DragonOS-Community/Rust-App-Template`即可创建项目
|
|
||||||
如果您的网络较慢,请使用镜像站`cargo generate --git https://git.mirrors.dragonos.org/DragonOS-Community/Rust-App-Template`
|
|
||||||
4. 使用`cargo run`来运行项目
|
|
||||||
5. 在DragonOS的`user/dadk/config`目录下,使用`dadk new`命令,创建编译配置,安装到DragonOS的`/`目录下。
|
|
||||||
(在dadk的编译命令选项处,请使用Makefile里面的`make install`配置进行编译、安装)
|
|
||||||
6. 编译DragonOS即可安装
|
|
@ -1,173 +0,0 @@
|
|||||||
use libc::{
|
|
||||||
bind, c_void, getpid, recvfrom, sendto, sockaddr, sockaddr_storage, socket, AF_NETLINK,
|
|
||||||
SOCK_CLOEXEC, SOCK_DGRAM,
|
|
||||||
};
|
|
||||||
use nix::libc;
|
|
||||||
use std::os::unix::io::RawFd;
|
|
||||||
use std::{io, mem};
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
struct Nlmsghdr {
|
|
||||||
nlmsg_len: u32,
|
|
||||||
nlmsg_type: u16,
|
|
||||||
nlmsg_flags: u16,
|
|
||||||
nlmsg_seq: u32,
|
|
||||||
nlmsg_pid: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_netlink_socket() -> io::Result<RawFd> {
|
|
||||||
let sockfd = unsafe {
|
|
||||||
socket(
|
|
||||||
AF_NETLINK,
|
|
||||||
SOCK_DGRAM | SOCK_CLOEXEC,
|
|
||||||
libc::NETLINK_KOBJECT_UEVENT,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if sockfd < 0 {
|
|
||||||
println!("Error: {}", io::Error::last_os_error());
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(sockfd)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bind_netlink_socket(sock: RawFd) -> io::Result<()> {
|
|
||||||
let pid = unsafe { getpid() };
|
|
||||||
let mut addr: libc::sockaddr_nl = unsafe { mem::zeroed() };
|
|
||||||
addr.nl_family = AF_NETLINK as u16;
|
|
||||||
addr.nl_pid = pid as u32;
|
|
||||||
addr.nl_groups = 0;
|
|
||||||
|
|
||||||
let ret = unsafe {
|
|
||||||
bind(
|
|
||||||
sock,
|
|
||||||
&addr as *const _ as *const sockaddr,
|
|
||||||
mem::size_of::<libc::sockaddr_nl>() as u32,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if ret < 0 {
|
|
||||||
println!("Error: {}", io::Error::last_os_error());
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send_uevent(sock: RawFd, message: &str) -> io::Result<()> {
|
|
||||||
let mut addr: libc::sockaddr_nl = unsafe { mem::zeroed() };
|
|
||||||
addr.nl_family = AF_NETLINK as u16;
|
|
||||||
addr.nl_pid = 0;
|
|
||||||
addr.nl_groups = 0;
|
|
||||||
|
|
||||||
let nlmsghdr = Nlmsghdr {
|
|
||||||
nlmsg_len: (mem::size_of::<Nlmsghdr>() + message.len()) as u32,
|
|
||||||
nlmsg_type: 0,
|
|
||||||
nlmsg_flags: 0,
|
|
||||||
nlmsg_seq: 0,
|
|
||||||
nlmsg_pid: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut buffer = Vec::with_capacity(nlmsghdr.nlmsg_len as usize);
|
|
||||||
buffer.extend_from_slice(unsafe {
|
|
||||||
std::slice::from_raw_parts(
|
|
||||||
&nlmsghdr as *const Nlmsghdr as *const u8,
|
|
||||||
mem::size_of::<Nlmsghdr>(),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
buffer.extend_from_slice(message.as_bytes());
|
|
||||||
|
|
||||||
let ret = unsafe {
|
|
||||||
sendto(
|
|
||||||
sock,
|
|
||||||
buffer.as_ptr() as *const c_void,
|
|
||||||
buffer.len(),
|
|
||||||
0,
|
|
||||||
&addr as *const _ as *const sockaddr,
|
|
||||||
mem::size_of::<libc::sockaddr_nl>() as u32,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if ret < 0 {
|
|
||||||
println!("Error: {}", io::Error::last_os_error());
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn receive_uevent(sock: RawFd) -> io::Result<String> {
|
|
||||||
// 检查套接字文件描述符是否有效
|
|
||||||
if sock < 0 {
|
|
||||||
println!("Invalid socket file descriptor: {}", sock);
|
|
||||||
return Err(io::Error::new(
|
|
||||||
io::ErrorKind::InvalidInput,
|
|
||||||
"Invalid socket file descriptor",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut buf = [0u8; 1024];
|
|
||||||
// let mut addr: sockaddr_storage = unsafe { mem::zeroed() };
|
|
||||||
// let mut addr_len = mem::size_of::<sockaddr_storage>() as u32;
|
|
||||||
|
|
||||||
// 检查缓冲区指针和长度是否有效
|
|
||||||
if buf.is_empty() {
|
|
||||||
println!("Buffer is empty");
|
|
||||||
return Err(io::Error::new(
|
|
||||||
io::ErrorKind::InvalidInput,
|
|
||||||
"Buffer is empty",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
let len = unsafe {
|
|
||||||
recvfrom(
|
|
||||||
sock,
|
|
||||||
buf.as_mut_ptr() as *mut c_void,
|
|
||||||
buf.len(),
|
|
||||||
0,
|
|
||||||
core::ptr::null_mut(), // 不接收发送方地址
|
|
||||||
core::ptr::null_mut(), // 不接收发送方地址长度
|
|
||||||
)
|
|
||||||
};
|
|
||||||
println!("Received {} bytes", len);
|
|
||||||
println!("Received message: {:?}", &buf[..len as usize]);
|
|
||||||
if len < 0 {
|
|
||||||
println!("Error: {}", io::Error::last_os_error());
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
let nlmsghdr_size = mem::size_of::<Nlmsghdr>();
|
|
||||||
if (len as usize) < nlmsghdr_size {
|
|
||||||
println!("Received message is too short");
|
|
||||||
return Err(io::Error::new(
|
|
||||||
io::ErrorKind::InvalidData,
|
|
||||||
"Received message is too short",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let nlmsghdr = unsafe { &*(buf.as_ptr() as *const Nlmsghdr) };
|
|
||||||
if nlmsghdr.nlmsg_len as isize > len {
|
|
||||||
println!("Received message is incomplete");
|
|
||||||
return Err(io::Error::new(
|
|
||||||
io::ErrorKind::InvalidData,
|
|
||||||
"Received message is incomplete",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let message_data = &buf[nlmsghdr_size..nlmsghdr.nlmsg_len as usize];
|
|
||||||
Ok(String::from_utf8_lossy(message_data).to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let socket = create_netlink_socket().expect("Failed to create Netlink socket");
|
|
||||||
println!("Netlink socket created successfully");
|
|
||||||
|
|
||||||
bind_netlink_socket(socket).expect("Failed to bind Netlink socket");
|
|
||||||
println!("Netlink socket created and bound successfully");
|
|
||||||
|
|
||||||
send_uevent(socket, "add@/devices/virtual/block/loop0").expect("Failed to send uevent message");
|
|
||||||
println!("Custom uevent message sent successfully");
|
|
||||||
|
|
||||||
let message = receive_uevent(socket).expect("Failed to receive uevent message");
|
|
||||||
println!("Received uevent message: {}", message);
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "test-uevent",
|
|
||||||
"version": "0.1.0",
|
|
||||||
"description": "",
|
|
||||||
"rust_target": null,
|
|
||||||
"task_type": {
|
|
||||||
"BuildFromSource": {
|
|
||||||
"Local": {
|
|
||||||
"path": "apps/test-uevent"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"depends": [],
|
|
||||||
"build": {
|
|
||||||
"build_command": "make install"
|
|
||||||
},
|
|
||||||
"install": {
|
|
||||||
"in_dragonos_path": "/"
|
|
||||||
},
|
|
||||||
"clean": {
|
|
||||||
"clean_command": "make clean"
|
|
||||||
},
|
|
||||||
"envs": [],
|
|
||||||
"build_once": false,
|
|
||||||
"install_once": false,
|
|
||||||
"target_arch": [
|
|
||||||
"x86_64"
|
|
||||||
]
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user