mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-09 07:06:47 +00:00
remove uevent and netlink
This commit is contained in:
parent
d7be7deebc
commit
4a2b5932cc
@ -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(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,24 +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实例
|
||||||
|
@ -6,12 +6,9 @@ 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,
|
||||||
libs::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
|
libs::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||||
@ -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 {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -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,405 +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();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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);
|
|
||||||
// todo: 设置了 UEVENT_HELP 编译条件之后,使用 handle_uevent_helper() 对指定的 uevent 进行处理,通常是热插拔程序 mdev、udev 等
|
|
||||||
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 {
|
|
||||||
// TODO: net namespace
|
|
||||||
// 如果有网络命名空间,则广播标记的uevent;如果没有,则广播未标记的uevent
|
|
||||||
let ret = uevent_net_broadcast_untagged(env, action_string, devpath);
|
|
||||||
log::info!("kobject_uevent_net_broadcast finish. ret: {}", ret);
|
|
||||||
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(None)));
|
|
||||||
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(None)));
|
|
||||||
|
|
||||||
// 锁定 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().inner.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().inner.is_empty() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log::info!("next is netlink_broadcast");
|
|
||||||
let netlink_socket = 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ use crate::{
|
|||||||
driver::base::{
|
driver::base::{
|
||||||
class::Class,
|
class::Class,
|
||||||
device::{
|
device::{
|
||||||
bus::Bus, driver::Driver, CommonAttrGroup, Device, DeviceCommonData, DeviceType,
|
bus::Bus, driver::Driver, Device, DeviceCommonData, DeviceType,
|
||||||
IdTable,
|
IdTable,
|
||||||
},
|
},
|
||||||
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
||||||
@ -87,7 +87,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>> {
|
||||||
|
@ -11,7 +11,7 @@ use crate::{
|
|||||||
base::{
|
base::{
|
||||||
class::Class,
|
class::Class,
|
||||||
device::{
|
device::{
|
||||||
bus::Bus, driver::Driver, CommonAttrGroup, Device, DeviceCommonData, DeviceType,
|
bus::Bus, driver::Driver, Device, DeviceCommonData, DeviceType,
|
||||||
IdTable,
|
IdTable,
|
||||||
},
|
},
|
||||||
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
||||||
@ -77,7 +77,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,7 +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},
|
||||||
@ -173,7 +173,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,7 +8,7 @@ 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,
|
||||||
},
|
},
|
||||||
@ -64,7 +64,7 @@ impl Class for TtyClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn dev_groups(&self) -> &'static [&'static dyn AttributeGroup] {
|
fn dev_groups(&self) -> &'static [&'static dyn AttributeGroup] {
|
||||||
return &[&CommonAttrGroup];
|
return &[];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ 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, IdTable,
|
DeviceCommonData, DeviceType, IdTable,
|
||||||
},
|
},
|
||||||
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
||||||
@ -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,342 +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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 创建一个新的内核netlink套接字
|
|
||||||
pub fn netlink_kernel_create(
|
|
||||||
unit: usize,
|
|
||||||
cfg: Option<NetlinkKernelCfg>,
|
|
||||||
) -> Result<NetlinkSock, SystemError> {
|
|
||||||
let mut nlk: NetlinkSock = NetlinkSock::new(Some(unit));
|
|
||||||
let sk: Arc<Mutex<NetlinkSock>> = Arc::new(Mutex::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.set_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 as usize)?;
|
|
||||||
Ok(Inode::new(socket))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// 用户空间创建一个新的Netlink套接字
|
|
||||||
fn create_netlink_socket(_protocol: usize) -> Result<Arc<dyn Socket>, SystemError> {
|
|
||||||
match _protocol {
|
|
||||||
NETLINK_KOBJECT_UEVENT => Ok(Arc::new(af_netlink::NetlinkSock::new(Some(_protocol)))),
|
|
||||||
_ => 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,44 +0,0 @@
|
|||||||
use super::af_netlink::{NetlinkSock, NetlinkSocket};
|
|
||||||
use crate::libs::{mutex::Mutex, rwlock::RwLock};
|
|
||||||
use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
|
||||||
use uefi_raw::protocol;
|
|
||||||
const SKB_SIZE: usize = 4096; // 定义 SKB 的大小
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct SkBuff {
|
|
||||||
pub sk: Arc<Mutex<NetlinkSock>>,
|
|
||||||
pub len: u32,
|
|
||||||
pub inner: Vec<u8>,
|
|
||||||
}
|
|
||||||
impl SkBuff {
|
|
||||||
pub fn new(protocol: Option<usize>) -> Self {
|
|
||||||
SkBuff {
|
|
||||||
sk: Arc::new(Mutex::new(NetlinkSock::new(protocol))),
|
|
||||||
len: 0,
|
|
||||||
inner: vec![0u8; SKB_SIZE],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理网络套接字的过度运行情况
|
|
||||||
pub fn netlink_overrun(sk: &Arc<Mutex<NetlinkSock>>) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 用于检查网络数据包(skb)是否被共享
|
|
||||||
pub fn skb_shared(skb: &RwLock<SkBuff>) -> bool {
|
|
||||||
// todo!()
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 处理被孤儿化的网络数据包(skb)
|
|
||||||
/// 孤儿化网络数据包意味着数据包不再与任何套接字关联,
|
|
||||||
/// 通常是因为发送数据包时指定了 MSG_DONTWAIT 标志,这告诉内核不要等待必要的资源(如内存),而是尽可能快地发送数据包。
|
|
||||||
pub fn skb_orphan(skb: &Arc<RwLock<SkBuff>>) {
|
|
||||||
// todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
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,10 +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 => {
|
|
||||||
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);
|
||||||
@ -289,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();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user