一.内核层的改动
1.1 头文件中加入NETLINK的命令
注意:这个必须得在头文件中申请,直接在.c文件中定义,上层在调用时会提示找不到
这个得再看一下内核代码,查一下原因
1.2 hello.c中
二.上层测试程序
2.1 netlinktest.c
2.2 Android.mk
三.源码下载
hello.rar (内核层)
test_netlinktest.rar (应用层)
四. 参考文章:
netlink socket编程实例
http://blog.chinaunix.net/uid-14753126-id-2983915.html
1.1 头文件中加入NETLINK的命令
- include/linux/netlink.h
- #define NETLINK_TEST 26
这个得再看一下内核代码,查一下原因
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;
- }
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