layout: post
title: netlink通信機(jī)制-內(nèi)核層
date: 2018-08-02 02:01:33
categories: kernel
tags: kernel
內(nèi)核層
處理函數(shù)注冊
struct netlink_kernel_cfg cfg = {
.input = nl_data_ready, /* set recv callback */
};
nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST, &cfg);
netlink_kernel_create 函數(shù)的使用具體跟內(nèi)核有關(guān)系,我這里是3.10的內(nèi)核秃症。
//2.6版本的
netlink_kernel_create(&init_net, NETLINK_TEST, 0, NULL, kernel_receive, THIS_MODULE);
//3.8后版本
netlink_kernel_create(&init_net, NETLINK_TEST, &cfg);
參數(shù)說明:
- 采用的固定的init_net,具體不知道為什么
- NETLINK_TEST 這個(gè)是netlink協(xié)議類型與用戶層的要相同
int skfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);應(yīng)用層的代碼
這個(gè)值取1~31 - cfg存放的是netlink內(nèi)核配置參數(shù)
接收數(shù)據(jù)
//處理消息的函數(shù)绒瘦,這個(gè)根據(jù)內(nèi)核版本也有變動(dòng)义桂,老版本的好像是struct sock *skb 類型
static void nl_data_ready(struct sk_buff *skb)
//獲取netlink數(shù)據(jù)包中netlink header的起始地址篙贸。
nlh = nlmsg_hdr(skb);
//獲取struct nlmsghdr結(jié)構(gòu)的數(shù)據(jù)部分
umsg = NLMSG_DATA(nlh);
發(fā)送數(shù)據(jù)
struct sk_buff *skb;
struct nlmsghdr *nlh;
// 為新的 sk_buffer申請空間
skb = nlmsg_new(slen, GFP_ATOMIC);
//用nlmsg_put()來設(shè)置netlink消息頭部
nlh = nlmsg_put(skb, 0, 0, NETLINK_TEST, slen, 0);
//拷貝數(shù)據(jù)
memcpy(nlmsg_data(nlh), message, slen);
//通過netlink_unicast()將消息發(fā)送用戶空間由pid所指定了進(jìn)程號的進(jìn)程
netlink_unicast(nl_sk, skb, pid, MSG_DONTWAIT);
源碼
/**
* @file: ktest.c
* @brief: kernel example
* @author: lflish
* @date: 2018-8-1
* @email: hxy.gold@gmail.com
* kernel version: 3.10.0-862
**/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/ip.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <net/sock.h>
#include <linux/netlink.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("lflish");
#define MAX_MSGSIZE 125
#define NETLINK_TEST 30
struct sock *nl_sk = NULL;
//向用戶空間發(fā)送消息的接口
int sendnlmsg(char *message,int pid)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
int slen = 0;
if(!message || !nl_sk){
return -1;
}
slen = strlen(message);
// 為新的 sk_buffer申請空間
skb = nlmsg_new(slen, GFP_ATOMIC);
if(!skb){
printk(KERN_ERR "my_net_link: alloc_skb Error./n");
return -2;
}
//用nlmsg_put()來設(shè)置netlink消息頭部
nlh = nlmsg_put(skb, 0, 0, NETLINK_TEST, slen, 0);
if(nlh == NULL){
printk("nlmsg_put failauer \n");
nlmsg_free(skb);
return -1;
}
memcpy(nlmsg_data(nlh), message, slen);
//通過netlink_unicast()將消息發(fā)送用戶空間由pid所指定了進(jìn)程號的進(jìn)程
netlink_unicast(nl_sk, skb, pid, MSG_DONTWAIT);
printk("send OK!\n");
return 0;
}
static void nl_data_ready(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);
sendnlmsg (kmsg, nlh->nlmsg_pid);
}
}
}
struct netlink_kernel_cfg cfg = {
.input = nl_data_ready, /* set recv callback */
};
int myinit_module(void)
{
printk("my netlink in\n");
nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST, &cfg);
if(nl_sk == NULL)
printk("kernel_create error\n");
return 0;
}
void mycleanup_module(void)
{
printk("my netlink out!\n");
sock_release(nl_sk->sk_socket);
netlink_kernel_release(nl_sk);
}
module_init(myinit_module);
module_exit(mycleanup_module);
MODULE_NAME :=ktest
obj-m :=$(MODULE_NAME).o
KERNELDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all: user kernel
kernel:
$(MAKE) -C $(KERNELDIR) M=$(PWD)
user: utest.c
gcc utest.c -o utest
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
rm -rf utest
以上是內(nèi)核的通信模型
參考文檔
結(jié)構(gòu)君珠、宏等說明實(shí)例 https://www.cnblogs.com/wenqiang/p/6306727.html
rfc3549 https://tools.ietf.org/html/rfc3549
這哥們的不錯(cuò)肾筐,但是是低版本內(nèi)核 http://blog.chinaunix.net/uid-23069658-id-3405954.html
https://wenku.baidu.com/view/4d6af81da417866fb84a8eb5.html