内核态程序
-
#include <linux/init.h>
-
#include <linux/module.h>
-
#include <linux/types.h>
-
#include <net/sock.h>
-
#include <linux/netlink.h>
-
#include <linux/kthread.h>
-
#include <linux/semaphore.h>
-
-
#define NETLINK_TEST 30
-
#define MSG_LEN 100
-
#define USER_PORT 66
-
#define GROUPID 5
-
-
struct sock *nlsk;
-
static struct task_struct *mythread = NULL; //内核线程对象
-
extern struct net init_net;
-
struct semaphore send_flag;
-
struct semaphore read_flag;
-
char *umsg = NULL;
-
int send_usrmsg(char *pbuf, uint16_t len,int pid)
-
{
-
struct sk_buff *nl_skb;
-
struct nlmsghdr *nlh; //消息头部
-
int ret=0;
-
//创建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), pbuf, len);
-
//ret = netlink_broadcast(nlsk, nl_skb, 0,5, GFP_KERNEL); //发送多播消息到多播组5,这里我故意没有用1之类的“常见”值,目的就是为了证明我们上面提到的多播组号和多播组号掩码之间的对应关系
-
ret = netlink_unicast(nlsk, nl_skb, pid, 0); //阻塞模式
-
if(ret < 0){
-
printk("netlink_unicast error, len:%d, retlen:%d \n",len, ret);
-
}
-
-
printk("send_usrmsg len:%d, retlen:%d \n",len, ret);
-
return ret;
-
}
-
-
int send_usrmsg_broadcast(char *pbuf, uint16_t len)
-
{
-
struct sk_buff *nl_skb;
-
struct nlmsghdr *nlh; //消息头部
-
int ret=0;
-
//创建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), pbuf, len);
-
ret = netlink_broadcast(nlsk, nl_skb, 0,GROUPID, GFP_KERNEL); //发送多播消息到多播组5,这里我故意没有用1之类的“常见”值,目的就是为了证明我们上面提到的多播组号和多播组号掩码之间的对应关系
-
if(ret < 0){
-
printk("netlink_broadcast error, len:%d, retlen:%d \n",len, ret);
-
}
-
-
printk("send_usrmsg len:%d, retlen:%d \n",len, ret);
-
return ret;
-
}
-
-
static void netlink_rcv_msg(struct sk_buff *skb)
-
{
-
struct nlmsghdr *nlh;
-
char *kmsg = "exit";
-
//从skb中获取data字段,并转换成nlh进行读取
-
nlh = nlmsg_hdr(skb);
-
//读取nlh后面的数据部分
-
umsg = NLMSG_DATA(nlh);
-
if(umsg){
-
printk("kernel recv from user: %s len:%d\n", umsg, (int)strlen(umsg));
-
printk("port id :%d\n",NETLINK_CB(skb).portid);
-
//send_usrmsg(kmsg, strlen(kmsg), NETLINK_CB(skb).portid); //给用户态发消息
-
}
-
up(&read_flag);
-
}
-
-
struct netlink_kernel_cfg cfg = {
-
.input = netlink_rcv_msg,
-
};
-
-
//每隔1分钟发送一条“I am from kernel!”消息,共发10个报文
-
static int sending_thread(void *data)
-
{
-
int i = 10;
-
struct completion cmpl;
-
char *kmsg = "I am from kernel";
-
int ret=0;
-
while((i--) > 0){
-
init_completion(&cmpl);
-
wait_for_completion_timeout(&cmpl, 30 * HZ);
-
ret = send_usrmsg_broadcast(kmsg, strlen(kmsg)); //给用户态发消息
-
if(ret<0){
-
continue;
-
}
-
printk("sending thread wait recvdata!\n");
-
down(&read_flag);
-
printk("sending thread recv data :%s!\n", umsg);
-
}
-
printk("sending thread exited!");
-
return 0;
-
}
-
-
static int __init test_netlink_broad_init(void)
-
{
-
nlsk = (struct sock *)netlink_kernel_create(&init_net,NETLINK_TEST, &cfg);
-
mythread = kthread_run(sending_thread,NULL,"thread_sender");
-
sema_init(&read_flag, 0);
-
return 0;
-
}
-
-
static void __exit test_netlink_broad_exit(void)
-
{
-
// 注销netlink协议
-
if(nlsk)
-
{
-
netlink_kernel_release(nlsk);
-
nlsk = NULL;
-
}
-
printk("exit......\n");
-
}
-
-
MODULE_LICENSE("GPL");
-
module_init(test_netlink_broad_init);
-
module_exit(test_netlink_broad_exit);
makefile 文件:
obj-m:=netlink_broad_kernel.o
CURRENT_PATH:=$(shell pwd)
LINUX_KERNEL:=$(shell uname -r)
LINUX_KERNEL_PATH:=/usr/src/kernels/$(LINUX_KERNEL)
#linux-headers-
all:
make
-C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
make
-C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean
用户态程序
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <sys/socket.h>
-
#include <string.h>
-
#include <linux/netlink.h>
-
#include <stdint.h>
-
#include <unistd.h>
-
#include <fcntl.h>
-
#include <errno.h>
-
#include <assert.h>
-
-
#define NETLINK_TEST 30
-
#define MSG_LEN 100
-
#define MAX_PLOAD 100
-
#define USER_PORT 66
-
#define GROUPID 5
-
typedef struct _user_msg_info
-
{
-
struct nlmsghdr hdr;
-
char msg[MSG_LEN];
-
} user_msg_info;
-
-
unsigned int netlink_group_mask(unsigned int group)
-
{
-
return group ? 1 << (group - 1) : 0;
-
}
-
-
int main(int argc,char **argv)
-
{
-
int sockfd;
-
struct sockaddr_nl saddr, daddr;
-
struct nlmsghdr *nlh;
-
user_msg_info u_info;
-
char *msg = "hello kernel, I am user process!";
-
socklen_t len;
-
-
//创建socket SOCK_RAW|SOCK_NONBLOCK
-
sockfd = socket(AF_NETLINK,SOCK_RAW, NETLINK_TEST);
-
-
//初始化地址
-
memset(&saddr,0,sizeof(saddr));
-
//地址赋值
-
saddr.nl_family = AF_NETLINK;
-
saddr.nl_pad = 0;
-
saddr.nl_pid = 0;// 表示我们要从内核接收多播消息。注意:该字段为0有双重意义,另一个意义是表示我们发送的数据的目的地址是内核。
-
saddr.nl_groups = netlink_group_mask(GROUPID); //组播ID
-
-
//地址与sockt绑定-bind
-
bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
-
-
//初始化目的地址
-
memset(&daddr, 0, sizeof(daddr));
-
daddr.nl_family = AF_NETLINK;
-
daddr.nl_pid = 0; // to kernel
-
daddr.nl_groups = 0;
-
//struct timeval tv= {10, 0};
-
struct timeval timeout;
-
timeout.tv_sec = 60;
-
timeout.tv_usec = 0;
-
-
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval ));
-
-
//初始化消息头
-
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 = USER_PORT; //self port
-
//nlh->nlmsg_pid = getpid();//我们希望得到内核回应,所以得告诉内核我们ID号
-
-
-
while (1)
-
{
-
memset(&u_info, 0, sizeof(u_info));
-
len = sizeof(struct sockaddr_nl);
-
-
//接收消息
-
int ret = recvfrom(sockfd,&u_info,sizeof(user_msg_info),0,(struct sockaddr *)&daddr,&len);
-
if(ret < 0){
-
printf("recvfrom error, errno:%d \n",errno);
-
break;
-
}
-
-
printf("recv from kernel:%s ret:%d\n",u_info.msg,ret);
-
if(strcmp("exit",u_info.msg) == 0){
-
printf("recv from kernel:%s exit .\n",u_info.msg);
-
break ;
-
}
-
-
//设置消息内容
-
memcpy(NLMSG_DATA(nlh),msg,strlen(msg));
-
-
//发送消息
-
ret = sendto(sockfd,nlh,nlh->nlmsg_len,0,(struct sockaddr *)&daddr,sizeof(struct sockaddr_nl));
-
if(ret < 0){
-
printf("sendto error, errno:%d \n", errno);
-
break;
-
}
-
printf("send to kernel :%s ret:%d nlmsg_len:%d \n",msg,ret, nlh->nlmsg_len);
-
-
};
-
-
close(sockfd);
-
return 0;
-
}
编译命令:
Gcc -o netlink_broad_user netlink_ broad_user.c
阅读(381) | 评论(0) | 转发(0) |