mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 14:16: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 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 __ACPI_TABLES_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)?;
|
||||
}
|
||||
// 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(());
|
||||
}
|
||||
|
||||
|
@ -1,19 +1,16 @@
|
||||
/// 引入Module
|
||||
use crate::{
|
||||
driver::{
|
||||
base::{
|
||||
device::{
|
||||
device_number::{DeviceNumber, Major},
|
||||
Device, DeviceError, IdTable, BLOCKDEVS,
|
||||
},
|
||||
map::{
|
||||
DeviceStruct, DEV_MAJOR_DYN_END, DEV_MAJOR_DYN_EXT_END, DEV_MAJOR_DYN_EXT_START,
|
||||
DEV_MAJOR_HASH_SIZE, DEV_MAJOR_MAX,
|
||||
},
|
||||
use crate::driver::{
|
||||
base::{
|
||||
device::{
|
||||
device_number::{DeviceNumber, Major},
|
||||
Device, DeviceError, IdTable, BLOCKDEVS,
|
||||
},
|
||||
map::{
|
||||
DeviceStruct, DEV_MAJOR_DYN_END, DEV_MAJOR_DYN_EXT_END, DEV_MAJOR_DYN_EXT_START,
|
||||
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};
|
||||
|
@ -2,8 +2,6 @@ use super::{
|
||||
bus::{bus_manager, Bus},
|
||||
Device, DeviceMatchName, DeviceMatcher, IdTable,
|
||||
};
|
||||
use crate::driver::base::uevent::kobject_uevent::kobject_uevent;
|
||||
use crate::driver::base::uevent::KobjectAction;
|
||||
use crate::{
|
||||
driver::base::{
|
||||
device::{bus::BusNotifyEvent, dd::DeviceAttrCoredump, device_manager},
|
||||
@ -220,7 +218,6 @@ impl DriverManager {
|
||||
})?;
|
||||
|
||||
// todo: 发送uevent,类型问题
|
||||
let _ = kobject_uevent(driver.clone() as Arc<dyn KObject>, KobjectAction::KOBJADD);
|
||||
// deferred_probe_extend_timeout();
|
||||
|
||||
return Ok(());
|
||||
|
@ -43,7 +43,6 @@ use super::{
|
||||
},
|
||||
kset::KSet,
|
||||
swnode::software_node_notify,
|
||||
uevent::UeventAttr,
|
||||
};
|
||||
|
||||
pub mod bus;
|
||||
@ -1026,25 +1025,6 @@ impl Eq 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! {
|
||||
/// 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());
|
||||
|
@ -1,7 +1,6 @@
|
||||
use core::{any::Any, fmt::Debug, hash::Hash, ops::Deref};
|
||||
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
string::String,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
@ -22,7 +21,7 @@ use crate::{
|
||||
|
||||
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 {
|
||||
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 {
|
||||
log::info!("get_kobj_path_length() kobj:{:?}", kobj.name());
|
||||
let mut length = 1;
|
||||
let mut parent = kobj.parent().unwrap().upgrade().unwrap();
|
||||
/* walk up the ancestors until we hit the one pointing to the
|
||||
* root.
|
||||
|
@ -6,11 +6,8 @@ use alloc::{
|
||||
|
||||
use core::hash::Hash;
|
||||
|
||||
use super::{
|
||||
kobject::{
|
||||
DynamicKObjKType, KObjType, KObject, KObjectManager, KObjectState, LockedKObjectState,
|
||||
},
|
||||
uevent::KobjUeventEnv,
|
||||
use super::kobject::{
|
||||
DynamicKObjKType, KObjType, KObject, KObjectManager, KObjectState, LockedKObjectState,
|
||||
};
|
||||
use crate::{
|
||||
filesystem::kernfs::KernFSInode,
|
||||
@ -29,8 +26,6 @@ pub struct KSet {
|
||||
/// 与父节点有关的一些信息
|
||||
parent_data: RwLock<KSetParentData>,
|
||||
self_ref: Weak<KSet>,
|
||||
/// kset用于发送uevent的操作函数集。kset能够发送它所包含的各种子kobj、孙kobj的消息,即kobj或其父辈、爷爷辈,都可以发送消息;优先父辈,然后是爷爷辈,以此类推
|
||||
pub uevent_ops: Option<Arc<dyn KSetUeventOps>>,
|
||||
}
|
||||
|
||||
impl Hash for KSet {
|
||||
@ -56,7 +51,6 @@ impl KSet {
|
||||
kobj_state: LockedKObjectState::new(None),
|
||||
parent_data: RwLock::new(KSetParentData::new(None, None)),
|
||||
self_ref: Weak::default(),
|
||||
uevent_ops: Some(Arc::new(KSetUeventOpsDefault)),
|
||||
};
|
||||
|
||||
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 subsys;
|
||||
pub mod swnode;
|
||||
pub mod uevent;
|
||||
|
@ -11,7 +11,7 @@ use crate::{
|
||||
bus::{Bus, BusState},
|
||||
device_manager,
|
||||
driver::Driver,
|
||||
CommonAttrGroup, Device, DeviceCommonData, DevicePrivateData, DeviceType, IdTable,
|
||||
Device, DeviceCommonData, DevicePrivateData, DeviceType, IdTable,
|
||||
},
|
||||
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
||||
kset::KSet,
|
||||
@ -331,6 +331,6 @@ impl Device for PlatformBusDevice {
|
||||
}
|
||||
|
||||
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::{
|
||||
bus::Bus,
|
||||
driver::{Driver, DriverCommonData},
|
||||
CommonAttrGroup, Device, DeviceCommonData, DeviceId, DeviceType, IdTable,
|
||||
Device, DeviceCommonData, DeviceId, DeviceType, IdTable,
|
||||
},
|
||||
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
||||
kset::KSet,
|
||||
@ -409,7 +409,7 @@ impl Device for VirtIOBlkDevice {
|
||||
}
|
||||
|
||||
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
||||
Some(&[&CommonAttrGroup])
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
driver::base::{
|
||||
class::{class_manager, Class},
|
||||
device::{sys_dev_char_kset, CommonAttrGroup},
|
||||
device::sys_dev_char_kset,
|
||||
kobject::KObject,
|
||||
subsys::SubSysPrivate,
|
||||
},
|
||||
@ -78,6 +78,6 @@ impl Class for NetClass {
|
||||
}
|
||||
|
||||
fn dev_groups(&self) -> &'static [&'static dyn AttributeGroup] {
|
||||
return &[&NetAttrGroup, &CommonAttrGroup];
|
||||
return &[&NetAttrGroup];
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ use crate::{
|
||||
device::{
|
||||
bus::Bus,
|
||||
driver::{Driver, DriverCommonData},
|
||||
CommonAttrGroup, Device, DeviceCommonData, DeviceId, DeviceType, IdTable,
|
||||
Device, DeviceCommonData, DeviceId, DeviceType, IdTable,
|
||||
},
|
||||
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
||||
kset::KSet,
|
||||
@ -251,7 +251,7 @@ impl Device for VirtIONetDevice {
|
||||
}
|
||||
|
||||
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
||||
Some(&[&CommonAttrGroup])
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,10 +8,7 @@ use alloc::{
|
||||
use crate::{
|
||||
driver::base::{
|
||||
class::Class,
|
||||
device::{
|
||||
bus::Bus, driver::Driver, CommonAttrGroup, Device, DeviceCommonData, DeviceType,
|
||||
IdTable,
|
||||
},
|
||||
device::{bus::Bus, driver::Driver, Device, DeviceCommonData, DeviceType, IdTable},
|
||||
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
||||
kset::KSet,
|
||||
},
|
||||
@ -87,7 +84,7 @@ impl PciDevice for PciGeneralDevice {
|
||||
|
||||
impl Device for PciGeneralDevice {
|
||||
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
||||
Some(&[&BasicPciReadOnlyAttrs, &CommonAttrGroup])
|
||||
Some(&[&BasicPciReadOnlyAttrs])
|
||||
}
|
||||
|
||||
fn bus(&self) -> Option<Weak<dyn Bus>> {
|
||||
|
@ -10,10 +10,7 @@ use crate::{
|
||||
driver::{
|
||||
base::{
|
||||
class::Class,
|
||||
device::{
|
||||
bus::Bus, driver::Driver, CommonAttrGroup, Device, DeviceCommonData, DeviceType,
|
||||
IdTable,
|
||||
},
|
||||
device::{bus::Bus, driver::Driver, Device, DeviceCommonData, DeviceType, IdTable},
|
||||
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
||||
kset::KSet,
|
||||
},
|
||||
@ -77,7 +74,7 @@ impl PciDevice for TestDevice {
|
||||
|
||||
impl Device for TestDevice {
|
||||
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
||||
Some(&[&HelloAttr, &CommonAttrGroup])
|
||||
Some(&[&HelloAttr])
|
||||
}
|
||||
|
||||
fn bus(&self) -> Option<Weak<dyn Bus>> {
|
||||
|
@ -9,7 +9,7 @@ use unified_init::macros::unified_init;
|
||||
use crate::{
|
||||
driver::base::{
|
||||
class::{class_manager, Class},
|
||||
device::{device_manager, sys_dev_char_kset, CommonAttrGroup},
|
||||
device::{device_manager, sys_dev_char_kset},
|
||||
kobject::KObject,
|
||||
subsys::SubSysPrivate,
|
||||
},
|
||||
@ -80,7 +80,7 @@ impl Class for RtcClass {
|
||||
return &self.subsystem;
|
||||
}
|
||||
fn dev_groups(&self) -> &'static [&'static dyn AttributeGroup] {
|
||||
return &[&CommonAttrGroup];
|
||||
return &[];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,8 +9,7 @@ use crate::{
|
||||
driver::base::{
|
||||
class::Class,
|
||||
device::{
|
||||
bus::Bus, device_manager, driver::Driver, CommonAttrGroup, Device, DeviceCommonData,
|
||||
DeviceType, IdTable,
|
||||
bus::Bus, device_manager, driver::Driver, Device, DeviceCommonData, DeviceType, IdTable,
|
||||
},
|
||||
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
||||
kset::KSet,
|
||||
@ -173,7 +172,7 @@ impl Device for RtcGeneralDevice {
|
||||
true
|
||||
}
|
||||
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
||||
Some(&[&RtcAttrGroup, &CommonAttrGroup])
|
||||
Some(&[&RtcAttrGroup])
|
||||
}
|
||||
|
||||
fn dev_parent(&self) -> Option<Weak<dyn Device>> {
|
||||
|
@ -8,11 +8,10 @@ use unified_init::macros::unified_init;
|
||||
use crate::{
|
||||
driver::base::{
|
||||
class::{class_manager, Class},
|
||||
device::{sys_dev_char_kset, CommonAttrGroup},
|
||||
device::sys_dev_char_kset,
|
||||
kobject::KObject,
|
||||
subsys::SubSysPrivate,
|
||||
},
|
||||
filesystem::sysfs::AttributeGroup,
|
||||
init::initcall::INITCALL_SUBSYS,
|
||||
};
|
||||
|
||||
@ -62,10 +61,6 @@ impl Class for TtyClass {
|
||||
fn subsystem(&self) -> &SubSysPrivate {
|
||||
return &self.subsystem;
|
||||
}
|
||||
|
||||
fn dev_groups(&self) -> &'static [&'static dyn AttributeGroup] {
|
||||
return &[&CommonAttrGroup];
|
||||
}
|
||||
}
|
||||
|
||||
/// 初始化帧缓冲区子系统
|
||||
|
@ -11,8 +11,8 @@ use crate::{
|
||||
base::{
|
||||
class::Class,
|
||||
device::{
|
||||
bus::Bus, device_manager, driver::Driver, CommonAttrGroup, Device,
|
||||
DeviceCommonData, DeviceType, IdTable,
|
||||
bus::Bus, device_manager, driver::Driver, Device, DeviceCommonData, DeviceType,
|
||||
IdTable,
|
||||
},
|
||||
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
||||
kset::KSet,
|
||||
@ -235,7 +235,7 @@ impl Device for FbConsoleDevice {
|
||||
}
|
||||
|
||||
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
||||
return Some(&[&AnonymousAttributeGroup, &CommonAttrGroup]);
|
||||
return Some(&[&AnonymousAttributeGroup]);
|
||||
}
|
||||
|
||||
fn dev_parent(&self) -> Option<Weak<dyn Device>> {
|
||||
|
@ -18,7 +18,7 @@ use crate::{
|
||||
device_manager,
|
||||
device_number::{DeviceNumber, Major},
|
||||
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},
|
||||
kset::KSet,
|
||||
@ -114,7 +114,7 @@ impl Class for GraphicsClass {
|
||||
}
|
||||
|
||||
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]> {
|
||||
Some(&[&FbDeviceAttrGroup, &CommonAttrGroup])
|
||||
Some(&[&FbDeviceAttrGroup])
|
||||
}
|
||||
|
||||
fn dev_parent(&self) -> Option<Weak<dyn Device>> {
|
||||
|
@ -5,7 +5,6 @@ use unified_init::macros::unified_init;
|
||||
|
||||
use crate::{
|
||||
driver::base::{
|
||||
device::CommonAttrGroup,
|
||||
kobject::{KObjType, KObject, KObjectManager, KObjectSysFSOps},
|
||||
kset::KSet,
|
||||
},
|
||||
@ -46,7 +45,7 @@ impl KObjType for IrqKObjType {
|
||||
}
|
||||
|
||||
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
||||
Some(&[&IrqAttrGroup, &CommonAttrGroup])
|
||||
Some(&[&IrqAttrGroup])
|
||||
}
|
||||
|
||||
fn release(&self, _kobj: Arc<dyn KObject>) {
|
||||
|
@ -2,7 +2,6 @@ use crate::{filesystem::vfs::InodeId, net::socket};
|
||||
use alloc::{string::String, sync::Arc};
|
||||
|
||||
pub use smoltcp::wire::IpEndpoint;
|
||||
pub use socket::netlink::endpoint::NetlinkEndpoint;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Endpoint {
|
||||
@ -14,8 +13,6 @@ pub enum Endpoint {
|
||||
Inode((Arc<socket::Inode>, String)),
|
||||
/// Unix传递id索引和path所用的端点
|
||||
Unixpath((InodeId, String)),
|
||||
/// NetLink端点
|
||||
Netlink(NetlinkEndpoint),
|
||||
}
|
||||
|
||||
/// @brief 链路层端点
|
||||
|
@ -6,7 +6,6 @@ mod endpoint;
|
||||
mod family;
|
||||
pub mod inet;
|
||||
mod inode;
|
||||
pub mod netlink;
|
||||
pub mod unix;
|
||||
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");
|
||||
}
|
||||
AF::Unix => socket::unix::Unix::socket(socket_type, protocol)?,
|
||||
AF::Netlink => socket::netlink::Netlink::socket(socket_type, protocol)?,
|
||||
_ => {
|
||||
todo!("unsupport address family");
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ use crate::{
|
||||
};
|
||||
|
||||
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::*;
|
||||
|
||||
|
@ -186,11 +186,6 @@ impl SockAddr {
|
||||
log::warn!("not support address family {:?}", addr.family);
|
||||
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);
|
||||
return Err(SystemError::EINVAL);
|
||||
@ -290,17 +285,6 @@ impl From<Endpoint> for SockAddr {
|
||||
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)) => {
|
||||
log::debug!("from unix path {:?}", path);
|
||||
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