使用netlink机制在内核与应用程序之间通信
前一段时间,在开发一个驱动程序的过程中,需要在驱动程序与应用程序之间进行通信。其中驱动程序在接收到一个硬件中断之后通知应用程序进行相应的处理。为 解决此类问题,驱动程序提供了几种机制:(1)使用copy_to_user/copy_from_user方法,缺点是通信响应时间过长(2)使用信 号,但是限于字符设备(3)使用netlink。
在linux2.4之后引入了netlink机制,它将是Linux用户态与内核态交流的主要方法之一。netlink 的特点是对中断过程的支持,也就是说,可以在中断程序中直接调用netlink相关函数。它在内核空间接收用户空间数据时不再需要用户自行启动一个内核线 程,而是通过另一个软中断调用用户事先指定的接收函数。netlink的通信过程如下:
下面分用户空间与内核空间2个部分讲述netlink的基本使用方法
1. 用户空间的程序
用户的应用程序使用标准套接字socket与内核空间进行通讯,标准socket API的函数, socket()、 bind()、sendmsg()、recvmsg() 和 close()很容易地应用到 netlink socket。
程序代码:
#define <include/linux/netlink.h>
struct u_packet_info
{
struct nlmsghdr hdr;
struct packet_info p_info;
};
struct u_packet_info info;
/*自定义消息首部,它仅包含了netlink的消息首部*/
struct msg_to_kernel
{
struct nlmsghdr hdr;
};
struct msg_to_kernel message;
static int skfd, kpeerlen, rcvlen;
struct sockaddr_nl local;
struct sockaddr_nl kpeer;
struct msg_to_kernel message;
skfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
if(skfd < 0)
{
printf("can not create a netlink socket/n");
exit(0);
}
memset(&local, 0, sizeof(local));
local.nl_family = AF_NETLINK;
local.nl_pid = getpid(); /*设置pid为自己的pid值*/
local.nl_groups = 0;
/*绑定套接字*/
if(bind(skfd, (struct sockaddr*)&local, sizeof(local)) != 0)
{
printf("bind() error/n");
return -1;
}
memset(&kpeer, 0, sizeof(kpeer));
kpeer.nl_family = AF_NETLINK;
kpeer.nl_pid = 0;
kpeer.nl_groups = 0;
memset(&message, 0, sizeof(message));
/*计算消息,因为这里只是发送一个请求消息,没有多余的数据,所以,数据长度为0*/
message.hdr.nlmsg_len = NLMSG_LENGTH(0);
message.hdr.nlmsg_flags = 0;
message.hdr.nlmsg_type = USER_TYPE; /*设置自定义消息类型*/