一.内核层的改动
1.1 头文件中加入NETLINK的命令
-
include/linux/netlink.h
-
#define NETLINK_TEST 26
注意:这个必须得在头文件中申请,直接在.c文件中定义,上层在调用时会提示找不到
这个得再看一下内核代码,查一下原因
1.2 hello.c中
-
#include <linux/init.h>
-
#include <linux/module.h>
-
#include <linux/workqueue.h>
-
#include <linux/device.h>
-
#include <linux/errno.h>
-
#include <linux/workqueue.h>
-
#include <linux/dma-mapping.h>
-
#include <linux/platform_device.h>
-
#include <linux/interrupt.h>
-
#include <linux/irqreturn.h>
-
#include <linux/types.h>
-
#include <linux/delay.h>
-
#include <linux/clk.h>
-
#include <linux/err.h>
-
#include <linux/io.h>
-
#include <linux/spinlock.h>
-
#include <linux/sched.h>
-
#include <linux/kthread.h>
-
#include <linux/wait.h>
-
-
#include <linux/netlink.h>
-
#include <net/netlink.h>
-
#include <net/net_namespace.h>
-
#include <linux/skbuff.h>
-
-
#define MAX_MSGSIZE 1024
-
//#define NETLINK_TEST 26
-
-
//static wait_queue_head_t mythread_wq;
-
struct task_struct *wait_thread_task;
-
-
static DEFINE_MUTEX(netlink_rx_mutex);
-
-
struct sock *nl_sk = NULL;
-
int pid;
-
-
void nl_data_recv(struct sk_buff *__skb)
-
{
-
struct sk_buff *skb;
-
struct nlmsghdr *nlh;
-
char str[100];
-
-
printk(KERN_NOTICE "cong: %s:%s[%d]: in func \n", __FILE__,__FUNCTION__, __LINE__);
-
mutex_lock(&netlink_rx_mutex);
-
skb = skb_get (__skb);
-
-
if(skb->len >= NLMSG_SPACE(0))
-
{
-
nlh = nlmsg_hdr(skb);
-
-
memcpy(str, NLMSG_DATA(nlh), sizeof(str));
-
printk("cong:%s:%s:%d, str=%s\n",__FILE__,__FUNCTION__, __LINE__,str);
-
-
// H stands for Hello message.
-
if(str[0] == 'P')
-
{
-
pid = nlh->nlmsg_pid;
-
//sendnlmsg("Hello reply.");
-
}
-
// E stands for Exit message
-
else if(str[0] == 'E')
-
{
-
pid = 0;
-
}
-
kfree_skb(skb);
-
}
-
mutex_unlock(&netlink_rx_mutex);
-
}
-
-
//向用户空间发送消息的接口
-
void nl_data_send(char *message,int dst_pid)
-
{
-
struct sk_buff *skb;
-
struct nlmsghdr *nlh;
-
int len = NLMSG_SPACE(MAX_MSGSIZE);
-
int slen = 0;
-
-
if(!message || !nl_sk){
-
return;
-
}
-
-
// 为新的 sk_buffer申请空间
-
skb = alloc_skb(len, GFP_KERNEL);
-
if(!skb){
-
printk("cong:%s:%s:%d, alloc_skb error\n",__FILE__,__FUNCTION__, __LINE__);
-
return;
-
}
-
-
slen = strlen(message)+1;
-
-
//用nlmsg_put()来设置netlink消息头部
-
nlh = nlmsg_put(skb, 0, 0, 0, MAX_MSGSIZE, 0);
-
-
// 设置Netlink的控制块
-
NETLINK_CB(skb).pid = 0; // 消息发送者的id标识,如果是内核发的则置0
-
NETLINK_CB(skb).dst_group = 0; //如果目的组为内核或某一进程,该字段也置0
-
-
message[slen] = '\0';
-
memcpy(NLMSG_DATA(nlh), message, slen+1);
-
-
printk("cong:%s:%s:%d, next send dst_pid=%d\n",__FILE__,__FUNCTION__, __LINE__, dst_pid);
-
//通过netlink_unicast()将消息发送用户空间由dst_pid所指定了进程号的进程
-
netlink_unicast(nl_sk, skb, dst_pid, 0);
-
printk("cong:%s:%s:%d, send ok\n",__FILE__,__FUNCTION__, __LINE__);
-
return;
-
}
-
-
static int my_wait_thread(void* data)
-
{
-
//char* buf = "hello,world\n";
-
while(1)
-
{
-
printk("cong:%s:%s:%d, in thread, pid=%d\n",__FILE__,__FUNCTION__, __LINE__, pid);
-
//发送者的进程ID我们已经将其存储在了netlink消息头部里的nlmsg_pid字段里,所以这里可以拿来用。
-
if(pid != 0)
-
nl_data_send("I see you", pid);
-
msleep(1000);
-
}
-
return 0;
-
}
-
-
-
static int __init hello_init(void)
-
{
-
int rc;
-
printk(KERN_ALERT "my first driver\n");
-
-
//extern struct sock *netlink_kernel_create(struct net *net, int unit,unsigned int groups,
-
// void (*input)(struct sk_buff *skb), struct mutex *cb_mutex, struct module *module);
-
//1. create a netlink
-
nl_sk= netlink_kernel_create(&init_net, NETLINK_1408_TRIGGER_TEST, 0,nl_data_recv, NULL, THIS_MODULE);
-
if(!nl_sk)
-
{
-
printk(KERN_NOTICE "cong: %s:%s[%d]: can't create netlink socket ", __FILE__,__FUNCTION__, __LINE__);
-
rc = -1;
-
goto fail;
-
}
-
-
wait_thread_task = kthread_create(my_wait_thread, NULL, "my_wait_thread");
-
if (IS_ERR(wait_thread_task)) {
-
return PTR_ERR(wait_thread_task);
-
}
-
wake_up_process(wait_thread_task);
-
return 0;
-
fail:
-
return rc;
-
}
-
-
static void __exit hello_exit(void)
-
{
-
printk(KERN_ALERT "goodbye my first dirver\n");
-
return ;
-
}
-
-
module_init(hello_init);
-
module_exit(hello_exit);
-
MODULE_LICENSE("GPL");
二.上层测试程序
2.1 netlinktest.c
-
#include <unistd.h>
-
#include <sys/stat.h>
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <sys/socket.h>
-
#include <sys/types.h>
-
#include <string.h>
-
#include <asm/types.h>
-
#include <linux/netlink.h>
-
#include <linux/socket.h>
-
-
//next defined must match kernel: include/linux/netlink.h
-
#define NETLINK_1408_TRIGGER_TEST 27
-
-
#define MAX_PAYLOAD 1024 /*消息最大负载为1024字节*/
-
static int create_and_sendmsg(struct nlmsghdr * nlh, struct msghdr msg)
-
{
-
struct sockaddr_nl dest_addr;
-
-
struct iovec iov;
-
int sock_fd=-1;
-
if(-1 == (sock_fd=socket(PF_NETLINK, SOCK_RAW,NETLINK_1408_TRIGGER_TEST)) )//创建套接字
-
{
-
perror("can't create netlink socket!");
-
return -1;
-
}
-
-
memset(&dest_addr, 0, sizeof(dest_addr));
-
dest_addr.nl_family = AF_NETLINK;
-
dest_addr.nl_pid = 0; /*我们的消息是发给内核的*/
-
dest_addr.nl_groups = 0; /*在本示例中不存在使用该值的情况*/
-
-
printf("next bind\n");
-
//将套接字和Netlink地址结构体进行绑定
-
if(-1 == bind(sock_fd, (struct sockaddr*)&dest_addr, sizeof(dest_addr))){
-
perror("can't bind sockfd with sockaddr_nl!");
-
return -1;
-
}
-
-
printf("%d: next malloc\n", __LINE__);
-
-
-
printf("%d: next memset\n", __LINE__);
-
memset(nlh,0,MAX_PAYLOAD);
-
/* 填充Netlink消息头部 */
-
nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
-
nlh->nlmsg_pid = getpid();//我们希望得到内核回应,所以得告诉内核我们ID号
-
nlh->nlmsg_type = NLMSG_NOOP; //指明我们的Netlink是消息负载是一条空消息
-
nlh->nlmsg_flags = 0;
-
-
printf("%d: next strcpy\n", __LINE__);
-
/*设置Netlink的消息内容,来自我们命令行输入的第一个参数*/
-
//strcpy(NLMSG_DATA(nlh), argv[1]);
-
strcpy(NLMSG_DATA(nlh), "P");
-
-
printf("%d: next memset\n", __LINE__);
-
/*这个是模板,暂时不用纠结为什么要这样用。有时间详细讲解socket时再说*/
-
memset(&iov, 0, sizeof(iov));
-
iov.iov_base = (void *)nlh;
-
iov.iov_len = nlh->nlmsg_len;
-
memset(&msg, 0, sizeof(msg));
-
msg.msg_iov = &iov;
-
msg.msg_iovlen = 1;
-
-
printf("next sendmsg\n");
-
sendmsg(sock_fd, &msg, 0); //通过Netlink socket向内核发送消息
-
return sock_fd;
-
}
-
-
int main(int argc, char* argv[])
-
{
-
//struct sockaddr_nl dest_addr;
-
struct nlmsghdr *nlh = NULL;
-
struct iovec iov;
-
int sock_fd=-1;
-
struct msghdr msg;
-
fd_set rset;
-
int maxfdp1, ret, stdineof;
-
if(NULL == (nlh=(struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD)))){
-
perror("alloc mem failed!");
-
return 1;
-
}
-
-
sock_fd = create_and_sendmsg(nlh, msg);
-
if(sock_fd < 0)
-
{
-
printf("create_and_sendmsg error %d\n", sock_fd);
-
return NULL;
-
}
-
-
/*这个是模板,暂时不用纠结为什么要这样用。有时间详细讲解socket时再说*/
-
memset(&iov, 0, sizeof(iov));
-
iov.iov_base = (void *)nlh;
-
iov.iov_len = nlh->nlmsg_len;
-
memset(&msg, 0, sizeof(msg));
-
msg.msg_iov = &iov;
-
msg.msg_iovlen = 1;
-
#if 0
-
FD_ZERO(&rset);
-
while(1)
-
{
-
FD_SET(sock_fd, &rset);
-
//maxfdp1 = max(fileno(fp), sock_fd)+1;
-
maxfdp1 = sock_fd+1;
-
//SLOGD("fd=%d,sockfd=%d,maxfdp1=%d",fileno(fp), sockfd, maxfdp1);
-
ret = select(maxfdp1, &rset, NULL, NULL, NULL);
-
if(ret <= 0)
-
continue;
-
if(FD_ISSET(sock_fd, &rset))
-
{
-
//接收内核消息的消息
-
printf("waiting message from kernel!\n");
-
memset((char*)NLMSG_DATA(nlh),0,1024);
-
//printf("next recvmsg\n");
-
recvmsg(sock_fd, &msg, 0);
-
printf("Got response: %s\n",NLMSG_DATA(nlh));
-
}
-
}
-
#endif
-
#if 1
-
while(1)
-
{
-
//接收内核消息的消息
-
printf("waiting message from kernel!,nlh=0x%x\n", nlh);
-
-
memset((char*)NLMSG_DATA(nlh),0,1024);
-
recvmsg(sock_fd,&msg,0);
-
printf("Got response: %s\n",NLMSG_DATA(nlh));
-
}
-
#endif
-
/* 关闭netlink套接字 */
-
close(sock_fd);
-
free(nlh);
-
return 0;
-
}
2.2 Android.mk
LOCAL_PATH
:= $
(call my
-dir
)
-
include $(CLEAR_VARS)
-
-
LOCAL_SRC_FILES:= netlinktest.c
-
-
LOCAL_SHARED_LIBRARIES := \
-
libutils liblog libcutils
-
-
# for asprinf
-
LOCAL_CFLAGS := -D_GNU_SOURCE
-
-
LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
-
-
LOCAL_MODULE:=netlinktest
-
include $(BUILD_EXECUTABLE)
三.源码下载
hello.rar (内核层)
test_netlinktest.rar (应用层)
四. 参考文章:
netlink socket编程实例
http://blog.chinaunix.net/uid-14753126-id-2983915.html
阅读(1933) | 评论(0) | 转发(0) |