Linux内核层:
kset_create_and_add //内核创建和注册kset
kobject_init //kobject初始化
kobject_add //初始化完成的 kobject 添加到内核中
kobject_uevent_env(obj, action, env) //上报给应用层
kobject_uevent默认会发送”ACTION=xxx”,”DEVPATH=xxx”,”SUBSYSTEM=xxx”这三个uevent环境变量,其中env可用如下方法赋值。
char*env[] = {NULL,NULL};
strcpy(buf,"USBEVENT=xxx_notify");
env[0] = buf;
其中action为enum kobject_action中的枚举值,在内核kobject.h中有定义
enum kobject_action {
KOBJ_ADD,
KOBJ_REMOVE,
KOBJ_CHANGE,
KOBJ_MOVE,
KOBJ_ONLINE,
KOBJ_OFFLINE,
KOBJ_BIND,
KOBJ_UNBIND,
};
应用层接收uevent消息代码示例:
#include <stdio.h>
#include <errno.h>
#include <stdbool.h>
#include <string.h>
#include <strings.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>#include <linux/netlink.h>
#define UEVENT_MSG_LEN 1024
int uevent_open_socket(int buf_sz, bool passcred)
{
struct sockaddr_nl addr;
int on = passcred;
int s;memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid();
addr.nl_groups = 0xffffffff;s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
if(s < 0)
return -1;setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &buf_sz, sizeof(buf_sz));
setsockopt(s, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0)
{
close(s);
return -1;
}return s;
}
ssize_t uevent_kernel_multicast_uid_recv(int socket, void *buffer,
size_t length, uid_t *user)
{
struct iovec iov = { buffer, length };
struct sockaddr_nl addr;
int len = sizeof(struct ucred);
char control[CMSG_SPACE(len)];
struct msghdr hdr =
{
&addr,
sizeof(addr),
&iov,
1,
control,
sizeof(control),
0,
};*user = -1;
ssize_t n = recvmsg(socket, &hdr, 0);
if (n <= 0)
{
return n;
}struct cmsghdr *cmsg = CMSG_FIRSTHDR(&hdr);
if (cmsg == NULL || cmsg->cmsg_type != 0x02) //SCM_CREDENTIALS = 0x02 //03_14
{
/* ignoring netlink message with no sender credentials */
goto out;
}struct ucred *cred = (struct ucred *)CMSG_DATA(cmsg);
*user = cred->uid;
if (cred->uid != 0)
{
/* ignoring netlink message from non-root user */
goto out;
}if (addr.nl_groups == 0 || addr.nl_pid != 0)
{
/* ignoring non-kernel or unicast netlink message */
goto out;
}return n;
out:
/* clear residual potentially malicious data */
bzero(buffer, length);
errno = EIO;
return -1;
}ssize_t uevent_kernel_multicast_recv(int socket, void *buffer, size_t length)
{
uid_t user = -1;
return uevent_kernel_multicast_uid_recv(socket, buffer, length, &user);
}int main(int argc, char *argv[])
{
int device_fd;
char msg[UEVENT_MSG_LEN+2];
int n;
int i;device_fd = uevent_open_socket(64*1024, true);
if(device_fd < 0)
return -1;while ((n = uevent_kernel_multicast_recv(device_fd, msg, UEVENT_MSG_LEN)) > 0) {
msg[n] = '\0';
msg[n+1] = '\0';for (i = 0; i < n; i++)
if (msg[i] == '\0')
msg[i] = ' ';printf("%s\n", msg);
}return 0;
}
编译成可执行应用程序后,运行,然后Linux底层驱动进行事件上报:
应用层收到信息如下:
online@/xxx/xxx_notify ACTION=online DEVPATH=/xxx/xxx_notify SUBSYSTEM=xxx USBEVENT=xxx_notify SEQNUM=633