1. 案例:笔者需要实现用户层与内核驱动模块adc.ko之间的通信,通信机制采用netlink;
2. 驱动模块adc.ko增加以下相应的定义及函数
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <net/sock.h>
#include <linux/netlink.h>
#define NETLINK_TEST 30
#define MSG_LEN 125
#define USER_PORT 100
struct sock *nlsk = NULL;
extern struct net init_net;
static int netlink_send_msg(char *buf, int len)
{
struct sk_buff *nl_skb;
struct nlmsghdr *nlh;
int ret;
/* 创建sk_buff 空间 */
nl_skb = nlmsg_new(len, GFP_ATOMIC);
if(!nl_skb)
{
printk("netlink alloc failure\n");
return -1;
}
/* 设置netlink消息头部 */
nlh = nlmsg_put(nl_skb, 0, 0, NETLINK_TEST, len, 0);
if(nlh == NULL)
{
printk("nlmsg_put failaure \n");
nlmsg_free(nl_skb);
return -1;
}
/* 拷贝数据发送 */
memcpy(nlmsg_data(nlh), buf, len);
ret = netlink_unicast(nlsk, nl_skb, USER_PORT, MSG_DONTWAIT);
return ret;
}
static void netlink_recv_msg(struct sk_buff *skb)
{
struct nlmsghdr *nlh = NULL;
char *umsg = NULL;
//char *kmsg = "hello users!!!";
if(skb->len >= nlmsg_total_size(0))
{
nlh = nlmsg_hdr(skb);
umsg = NLMSG_DATA(nlh);
if(umsg)
{
//printk("kernel recv from user: %s\n", umsg);
netlink_send_msg((char*)&g_hardware_version, 1);
}
}
}
struct netlink_kernel_cfg cfg = {
.input = netlink_recv_msg, /* set recv callback */
};
static int __init init_adc_netlink(void)
{
nlsk = (struct sock *)netlink_kernel_create(&init_net, NETLINK_TEST, &cfg);
if(nlsk == NULL){
printk("netlink_kernel_create error !\n");
return -1;
}
printk("init_adc_netlink ok.\n");
return 0;
}
static void exit_adc_net_link(void)
{
if (nlsk){
netlink_kernel_release(nlsk); /* release ..*/
nlsk = NULL;
}
printk("exit_adc_net_link ok!\n");
}
module_init(init_adc_netlink);
module_exit(exit_adc_net_link);
3. 应用程序增加获取内核模块的接口函数
#define NETLINK_TEST 30
#define MSG_LEN 125
#define MAX_PLOAD 125
typedef struct _user_msg_info{
struct nlmsghdr hdr;
char msg[MSG_LEN];
} user_msg_info;
//描述:获取硬件的版本
//参数:@pbHardVer 返回的硬件版本
//返回:成功返回true,反之为false
bool GetHardVerByAdc(BYTE *pbHardVer)
{
int skfd;
int ret;
user_msg_info u_info;
socklen_t len;
struct nlmsghdr *nlh = NULL;
struct sockaddr_nl saddr, daddr;
char *umsg = "hello netlink!!";
/* 创建NETLINK socket */
skfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);
if(skfd == -1)
{
perror("create socket error\n");
return false;
}
memset(&saddr, 0, sizeof(saddr));
saddr.nl_family = AF_NETLINK; //AF_NETLINK
saddr.nl_pid = 100; //端口号(port ID)
saddr.nl_groups = 0;
if(bind(skfd, (struct sockaddr *)&saddr, sizeof(saddr)) != 0)
{
perror("bind() error\n");
close(skfd);
return false;
}
memset(&daddr, 0, sizeof(daddr));
daddr.nl_family = AF_NETLINK;
daddr.nl_pid = 0; // to kernel
daddr.nl_groups = 0;
nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PLOAD));
memset(nlh, 0, sizeof(struct nlmsghdr));
nlh->nlmsg_len = NLMSG_SPACE(MAX_PLOAD);
nlh->nlmsg_flags = 0;
nlh->nlmsg_type = 0;
nlh->nlmsg_seq = 0;
nlh->nlmsg_pid = saddr.nl_pid; //self port
memcpy(NLMSG_DATA(nlh), umsg, strlen(umsg));
ret = sendto(skfd, nlh, nlh->nlmsg_len, 0, (struct sockaddr *)&daddr, sizeof(struct sockaddr_nl));
if(!ret)
{
perror("sendto error\n");
close(skfd);
return false;
}
//printf("send kernel:%s\n", umsg);
memset(&u_info, 0, sizeof(u_info));
len = sizeof(struct sockaddr_nl);
ret = recvfrom(skfd, &u_info, sizeof(user_msg_info), 0, (struct sockaddr *)&daddr, &len);
if(!ret)
{
perror("recv form kernel error\n");
close(skfd);
return false;
}
//printf("from kernel:%s, %02x\n", u_info.msg, u_info.msg);
*pbHardVer = u_info.msg[0];
close(skfd);
free((void *)nlh);
return true;
}
void main()
{
BYTE bHardware;
if (GetHardVerByAdc(&bHardware))
printf("GetHardVerByAdc ok bHardware=%0d.\n", bHardware);
}
4. 运行接口
GetHardVerByAdc ok bHardware=126.