Merge pull request #980 from val213/feat-network-rebuild

remove(uevent): 将 netlink/uevent 机制从网络子分支中暂时移除
This commit is contained in:
Samuel Dai 2024-10-16 15:47:35 +08:00 committed by GitHub
commit 10e62c7a47
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
41 changed files with 38 additions and 3104 deletions

View File

@ -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(());
}

View File

@ -1,6 +1,5 @@
/// 引入Module
use crate::{
driver::{
use crate::driver::{
base::{
device::{
device_number::{DeviceNumber, Major},
@ -12,8 +11,6 @@ use crate::{
},
},
block::cache::{cached_block_device::BlockCache, BlockCacheError, BLOCK_SIZE},
},
filesystem::sysfs::AttributeGroup,
};
use alloc::{string::String, sync::Arc, vec::Vec};

View File

@ -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(());

View File

@ -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());

View File

@ -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.

View File

@ -6,11 +6,8 @@ use alloc::{
use core::hash::Hash;
use super::{
kobject::{
use super::kobject::{
DynamicKObjKType, KObjType, KObject, KObjectManager, KObjectState, LockedKObjectState,
},
uevent::KobjUeventEnv,
};
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
}
}

View File

@ -12,4 +12,3 @@ pub mod map;
pub mod platform;
pub mod subsys;
pub mod swnode;
pub mod uevent;

View File

@ -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
}
}

View File

@ -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 消息的 skbsocket 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
}

View File

@ -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两个回调函数用处如下
/*
filterKobject需要上报uevent时kset可以通过该接口过滤event
namekset的名称kset没有合法的名称Kobject将不允许上报uvent
ueventKobject需要上报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())
}

View File

@ -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
}
}

View File

@ -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];
}
}

View File

@ -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
}
}

View File

@ -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>> {

View File

@ -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>> {

View File

@ -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 &[];
}
}

View File

@ -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>> {

View File

@ -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];
}
}
/// 初始化帧缓冲区子系统

View File

@ -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>> {

View File

@ -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>> {

View File

@ -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>) {

View File

@ -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 链路层端点

View File

@ -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

View File

@ -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 {}

View File

@ -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 }
}
}

View File

@ -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),
}
}

View File

@ -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);
}

View File

@ -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() {}

View File

@ -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
}

View File

@ -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");
}

View File

@ -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::*;

View File

@ -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();

View File

@ -1,2 +0,0 @@
[build]
target = "x86_64-unknown-linux-musl"

View File

@ -1,3 +0,0 @@
/target
Cargo.lock
/install/

View File

@ -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"

View File

@ -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

View File

@ -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即可安装

View File

@ -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);
}

View File

@ -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"
]
}