国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

內(nèi)核與用戶空間的通信實(shí)現(xiàn)—netlink

這篇具有很好參考價值的文章主要介紹了內(nèi)核與用戶空間的通信實(shí)現(xiàn)—netlink。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

前言

? ? ? ? netlink是一個內(nèi)核空間與用戶空間通信的機(jī)制,相對ioctl和procfs方式來說,netlink有很多優(yōu)點(diǎn):

  • netlink使用簡單,與UDO的socket編程類似,直接使用socket編程的API即可。只需要自定義一個新類型的 netlink 協(xié)議定義即可。
  • netlink是一種異步通信機(jī)制,在內(nèi)核與用戶態(tài)應(yīng)用之間傳遞的消息保存在socket緩存隊(duì)列中,發(fā)送消息只是把消息保存在接收者的socket的接收隊(duì)列,而不需要等待接收者收到消息。
  • netlink 支持多播,內(nèi)核模塊或應(yīng)用可以把消息多播給一個netlink組。
  • 內(nèi)核可以使用 netlink 首先發(fā)起會話。

? ? ? ? netlink通信的用戶程序與平時使用的UDPsocket類似,只是多了幾個結(jié)構(gòu)體,在剛開始學(xué)習(xí)netlink時被那么多結(jié)構(gòu)體間的關(guān)系搞的頭腦爆炸,很重要的一點(diǎn)也是在學(xué)習(xí)UDPsocket時沒有打好基礎(chǔ),就正如sendto、sendmsg的使用。

? ? ? ? 只要一開始能搞清楚整個netlink通信的創(chuàng)建和交互過程就能很容易理解。關(guān)于netlink更全面的理解大家自行百度,本文單純從編程角度入手,只是簡單介紹一下基礎(chǔ)的流程實(shí)現(xiàn)。

netlink編程

應(yīng)用程序

流程圖

sockaddr_nl,驅(qū)動開發(fā),嵌入式,linux,網(wǎng)絡(luò)

?圖1.sendto發(fā)送信息流程圖

sockaddr_nl,驅(qū)動開發(fā),嵌入式,linux,網(wǎng)絡(luò)

圖2.sendmsg發(fā)送信息流程圖?

socket()

/* 函數(shù)原型就是socket編程中的socket()函數(shù),就不介紹函數(shù)原型了,只介紹netlink相關(guān)。
 * 創(chuàng)建netlink套接字
 * SOCK_RAW表示原始的數(shù)據(jù)流
 * NETLINK_TEST是自己定義的一個宏,用來標(biāo)識協(xié)議號,也可以用定義在linux/netlink.h中內(nèi)核預(yù)留的宏NETLINK_GENERIC,實(shí)際上就是定義一個內(nèi)核還沒占用的數(shù)字。
 */
sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST)

bind()

/* 函數(shù)原型就是socket編程中的bind()函數(shù),就不介紹函數(shù)原型了,只介紹netlink相關(guān)。
 * 用戶程序進(jìn)程綁定sockaddr_nl元素
 * saddr是struct sockaddr_nl的一個結(jié)構(gòu)體元素,是netlink專用的地址結(jié)構(gòu)體。
 */
bind(sock_fd, (struct sockaddr*)&saddr, sizeof(saddr))

????????Struct?sockaddr_ln為Netlink的地址,和我們通常socket編程中的sockaddr_in作用一樣sockaddr_nl,驅(qū)動開發(fā),嵌入式,linux,網(wǎng)絡(luò)

struct sockaddr_nl
{
    sa_family_t nl_family; /*該字段總是為AF_NETLINK */
    unsigned short nl_pad; /* 目前未用到,填充為0*/
    __u32 nl_pid;          /* PORT-ID 用來標(biāo)識單播地址,是netlink通信標(biāo)識,類似于ip地址,0表示內(nèi)核*/
    __u32 nl_groups;       /* 多播使用,0表示不用多播 */
};

創(chuàng)建struct nlmsghdr

/* netlink通信的報(bào)文分為消息頭和消息體。
 * netlink與tcp、udp的通信區(qū)別就是netlink的報(bào)文需要自己定義頭部信息。
 * 而tcp、udp的socket直接發(fā)送消息內(nèi)容,內(nèi)核協(xié)議棧會根據(jù)源、目的地址(sockaddr_in)自己填充頭部信息。 
 * netlink的消息頭就是結(jié)構(gòu)體nlmsghdr。 
 */
struct nlmsghdr
{
    __u32        nlmsg_len;      // 整個消息的長度,包括消息頭
    __u16        nlmsg_type;     // 消息的類型,區(qū)別數(shù)據(jù)消息還是控制消息
    __u16        nlmsg_flags;    // 附加在消息上的額外說明
    __u32        nlmsg_seq;      // 消息序列號,防止消息丟失
    __u32        nlmsg_pid;      // 用來表示自己的進(jìn)程標(biāo)識。為netlink連接通道唯一數(shù)字標(biāo)識符,用于避免內(nèi)核發(fā)送給用戶進(jìn)程時發(fā)錯對象,通常是用戶進(jìn)程的pid。
};

nlmsg_type:
#define NLMSG_NOOP      0x1      //不執(zhí)行任何動作,必須將該消息丟棄;
#define NLMSG_ERROR     0x2      //消息發(fā)生錯誤;
#define NLMSG_DONE      0x3      //標(biāo)識分組消息的末尾;
#define NLMSG_OVERRUN   0x4      //緩沖區(qū)溢出,表示某些消息已經(jīng)丟失。
define NLMSG_MIN_TYPE   0x10     //預(yù)留
        
nlmsg_flags:
#define NLM_F_REQUEST      1    // It is request message.
#define NLM_F_MULTI        2    // Multipart message, terminated by NLMSG_DONE 
#define NLM_F_ACK          4    // Reply with ack, with zero or error code
#define NLM_F_ECHO         8    // Echo this request
#define NLM_F_DUMP_INTR    16   // Dump was inconsistent due to sequence change
 
// Modifiers to GET request
#define NLM_F_ROOT      0x100   // specify tree    root
#define NLM_F_MATCH     0x200   // return all matching
#define NLM_F_ATOMIC    0x400   // atomic GET
#define NLM_F_DUMP    (NLM_F_ROOT|NLM_F_MATCH)
 
// Modifiers to NEW request 
#define NLM_F_REPLACE   0x100   //Override existing
#define NLM_F_EXCL      0x200   // Do not touch, if it exists
#define NLM_F_CREATE    0x400   // Create, if it does not exist
#define NLM_F_APPEND    0x800   // Add to end of list

注意:struct nlmsghdr結(jié)構(gòu)體中

? ? __u32 ? ? ? ?nlmsg_pid; ? ? ?// 用來表示自己的進(jìn)程標(biāo)識。

????????內(nèi)核通過獲取這個值知道用戶進(jìn)程的標(biāo)識,然后通過netlink_unicast的第三個參數(shù)pid發(fā)送出去。

? ? ? ? 需要注意的是內(nèi)核設(shè)置消息頭的結(jié)構(gòu)體nlmsg_put第四個參數(shù)設(shè)置nlmsg_pid應(yīng)為0,標(biāo)識自己的pid為0級內(nèi)核。

????????我們在創(chuàng)建netlink報(bào)文消息頭nlsmhdr結(jié)構(gòu)體時會一起申請消息體的結(jié)構(gòu)。

struct nlmsghdr *nlh = NULL; //定義netlink消息頭類型的指針
nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD)); // 申請netlink報(bào)文空間:消息頭+消息體。NLMSG_SPACE是系統(tǒng)頭文件定義的宏,后面會介紹netlink通信常用的宏;MAX_PAYLOAD是用戶自己定義的消息負(fù)載大小

netlink常用的系統(tǒng)定義的宏

#define NLMSG_ALIGNTO   4U

/* 宏NLMSG_ALIGN(len)用于得到不小于len且字節(jié)對齊的最小數(shù)值 */
#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )

/* Netlink 頭部長度 */
#define NLMSG_HDRLEN     ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))

/* 計(jì)算消息數(shù)據(jù)len的真實(shí)消息長度(消息體 + 消息頭)*/
#define NLMSG_LENGTH(len) ((len) + NLMSG_HDRLEN)

/* 宏NLMSG_SPACE(len)返回不小于NLMSG_LENGTH(len)且字節(jié)對齊的最小數(shù)值 */
#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))

/* 宏NLMSG_DATA(nlh)用于取得消息的數(shù)據(jù)部分的首地址,設(shè)置和讀取消息數(shù)據(jù)部分時需要使用該宏 */
#define NLMSG_DATA(nlh)  ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))

/* 宏NLMSG_NEXT(nlh,len)用于得到下一個消息的首地址, 同時len 變?yōu)槭S嘞⒌拈L度 */
#define NLMSG_NEXT(nlh,len)  ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \(struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))

/* 判斷消息是否 >len */
#define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \(nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \(nlh)->nlmsg_len <= (len))

/* NLMSG_PAYLOAD(nlh,len) 用于返回payload的長度*/
#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))

sendto、recvfrom

/* sendto函數(shù)原型 */
int sendto(int s, const void * msg, int len, unsigned int flags, const struct sockaddr * to, int tolen);

/* netlink使用
 * sock_fd : socket函數(shù)創(chuàng)建的fd。
 * nlh : nlmsghdr結(jié)構(gòu)體指針
 * nlh->nlmsg_le : netlink報(bào)文長度
 * 0 : flag
 * daddr : 目的地址
 * sizeof(struct sockaddr_nl) : daddr元素大小
 */
sendto(sock_fd, nlh, nlh->nlmsg_len, 0, (struct sockaddr *)&daddr, sizeof(struct         sockaddr_nl));
/* recvfrom函數(shù)原型 */
int recvfrom(socket s,void *buf,int len,unsigned int flags, struct sockaddr *from,int *fromlen);

/* netlink使用 */
recvfrom(sock_fd, nlh, NLMSG_LENGTH(MAX_PAYLOAD), 0, NULL, NULL);

sendmsg、recvmsg

? ? ? ? netlink用戶程序發(fā)送和接收消息可以用sendto/sendmsg、recvfrom/recvmsg。使用sendto和recvfrom則如上所述。如果使用sendmsg和recvmsg就需要用到msghdr結(jié)構(gòu)體和iovec結(jié)構(gòu)體。sendmsg、recvmsg更為復(fù)雜功能更強(qiáng)。msghdr、nlmsghdr、iovec的關(guān)系如下圖所示:

sockaddr_nl,驅(qū)動開發(fā),嵌入式,linux,網(wǎng)絡(luò)

? ? ? ? ?下面我們來介紹一下msghdr與iovec結(jié)構(gòu)體

struct iovec 
{                    /* Scatter/gather array items */
    void  *iov_base;              /* Starting address */
    size_t iov_len;               /* Number of bytes to transfer */
};
/* iov_base: iov_base指向數(shù)據(jù)包緩沖區(qū),即參數(shù)buff,iov_len是buff的長度。msghdr中允許一次傳遞多個buff,以數(shù)組的形式組織在 msg_iov中,msg_iovlen就記錄數(shù)組的長度 (即有多少個buff)*/ 

struct msghdr 
{
    void         *msg_name;        // 數(shù)據(jù)的目的地址,網(wǎng)絡(luò)包指向sockaddr_in, netlink則指向sockaddr_nl; 
    socklen_t     msg_namelen;    // msg_namelen: msg_name 所代表的地址長度
    struct iovec *msg_iov;        // 指向的是緩沖區(qū)數(shù)組
    size_t        msg_iovlen;     // 緩沖區(qū)數(shù)組長度 
    void         *msg_control;    // 輔助數(shù)據(jù),控制信息(發(fā)送任何的控制信息) 
    size_t        msg_controllen; // 輔助信息長度 
    int           msg_flags;      // 消息標(biāo)識
};

/* iovec、msghdr結(jié)構(gòu)體的使用 */
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;

? ? ? ? sendmsg與recvmsg的使用

/* sendmsg函數(shù)原型 */
ssize_t sendmsg(int sockfd, struct msghdr *msg, int flags);

sendmsg(sock_fd, &msg, 0); //sock_fd為socket創(chuàng)建的fd,msg為msghdr的指針

/* recvmsg函數(shù)原型 */
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

recvmsg(sock_fd, &msg, 0);

用戶程序代碼-usr_netlink_demo.c

使用sendto、recvfrom

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/socket.h>

#define MAX_PAYLOAD 1024 /* netlink消息最大負(fù)載為1024B */
#define NETLINK_TEST 30

int main(int argc, char **argv)
{
	struct sockaddr_nl daddr;
	struct sockaddr_nl saddr; //定義netlink用戶空間地址體
	struct nlmsghdr *nlh = NULL; //定義netlink消息頭類型的指針
	
	int sock_fd = -1;
	int len;
	int ret;
	char recv_buf[MAX_PAYLOAD] = {0};
	char *umsg = "hello";

	/* 創(chuàng)建netlink套接字,SOCK_RAW表示原始的數(shù)據(jù)流,NETLINK_TEST表示用戶自定義協(xié)議 */
	if (-1 == (sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST)))
	{
		perror("can't create netlink socket!");
		return -1;
	}
	memset(&saddr, 0, sizeof(saddr));
	saddr.nl_family = AF_NETLINK;
	saddr.nl_pid = 100;
	saddr.nl_groups = 0;
	
	memset(&daddr, 0, sizeof(daddr));
	daddr.nl_family = AF_NETLINK;
	daddr.nl_pid = 0; // to kernel 
	daddr.nl_groups = 0;
	
	if (-1 == bind(sock_fd, (struct sockaddr*)&saddr, sizeof(saddr)))
	{
		perror("can't bind sockfd with sockaddr_nl!");
		return -2;
	}
	
	/* 
		給結(jié)構(gòu)體指針nlh分配地址
		NLMSG_SPACE(MAX_PAYLOAD): 該宏用于返回不小于MAX_PAYLOAD且4字節(jié)對齊的最小長度值
		一般用于向內(nèi)存系統(tǒng)申請空間是指定所申請的內(nèi)存字節(jié)數(shù)
	*/
	if (NULL == (nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD))))
	{
		perror("malloc mem failed!");
		return -3;
	}
	memset(nlh, 0, sizeof(struct nlmsghdr));
	nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
	nlh->nlmsg_pid = 100;
	nlh->nlmsg_type = 0;
	nlh->nlmsg_flags = 0;
	nlh->nlmsg_seq = 0;
	
	memcpy(NLMSG_DATA(nlh), umsg, strlen(umsg));
	
	ret = sendto(sock_fd, nlh, nlh->nlmsg_len, 0, (struct sockaddr *)&daddr, sizeof(struct sockaddr_nl));
	if(0 >= ret)
	{
		perror("sendto error\n");
		ret = -4;
		goto CleanUp;
	}

	memset(nlh,0,NLMSG_SPACE(MAX_PAYLOAD));
	
	len = sizeof(struct sockaddr_nl);
	ret = recvfrom(sock_fd, nlh, NLMSG_LENGTH(MAX_PAYLOAD), 0, NULL, NULL);
	if(0 >= ret)
	{
		perror("recvfrom kernel error\n");
		ret = -5;
		goto CleanUp;
	}
    printf("usr recv kernel:%s\n",NLMSG_DATA(nlh));
    ret = 0;
	
CleanUp:
	close(sock_fd);
	free(nlh);
	return ret;
}

使用sendmsg、recvmsg文章來源地址http://www.zghlxwxcb.cn/news/detail-589724.html

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/socket.h>

#define MAX_PAYLOAD 1024 /* netlink消息最大負(fù)載為1024B */
#define NETLINK_TEST 30

int main(int argc, char **argv)
{
	struct sockaddr_nl daddr;
	struct sockaddr_nl saddr; //定義netlink用戶空間地址體
	struct nlmsghdr *nlh = NULL; //定義netlink消息頭類型的指針
	struct iovec iov; //定義一個向量元素,通常用于多元素的數(shù)組
	struct msghdr msg; // 用于recvmsg、sendmsg發(fā)送和接受的數(shù)據(jù)存放;
	
	int sock_fd = -1;
	int len;
	int ret;
	char recv_buf[MAX_PAYLOAD] = {0};
	char *umsg = "hello";

	/* 創(chuàng)建netlink套接字,SOCK_RAW表示原始的數(shù)據(jù)流,NETLINK_TEST表示用戶自定義協(xié)議 */
	if (-1 == (sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST)))
	{
		perror("can't create netlink socket!");
		return -1;
	}
	memset(&saddr, 0, sizeof(saddr));
	saddr.nl_family = AF_NETLINK;
	saddr.nl_pid = 100;
	saddr.nl_groups = 0;
	
	memset(&daddr, 0, sizeof(daddr));
	daddr.nl_family = AF_NETLINK;
	daddr.nl_pid = 0; // to kernel 
	daddr.nl_groups = 0;
	
	if (-1 == bind(sock_fd, (struct sockaddr*)&saddr, sizeof(saddr)))
	{
		perror("can't bind sockfd with sockaddr_nl!");
		return -2;
	}
	
	/* 
		給結(jié)構(gòu)體指針nlh分配地址
		NLMSG_SPACE(MAX_PAYLOAD): 該宏用于返回不小于MAX_PAYLOAD且4字節(jié)對齊的最小長度值
		一般用于向內(nèi)存系統(tǒng)申請空間是指定所申請的內(nèi)存字節(jié)數(shù)
	*/
	if (NULL == (nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD))))
	{
		perror("malloc mem failed!");
		return -3;
	}
	memset(nlh, 0, sizeof(struct nlmsghdr));
	nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
	nlh->nlmsg_pid = 100;
	nlh->nlmsg_type = 0;
	nlh->nlmsg_flags = 0;
	nlh->nlmsg_seq = 0;
	
	memcpy(NLMSG_DATA(nlh), umsg, strlen(umsg));
	
	memset(&iov, 0, sizeof(iov));
	iov.iov_base = (void *)nlh;
	iov.iov_len = nlh->nlmsg_len;
	memset(&msg, 0, sizeof(msg));
    msg.msg_name = (void *)&(daddr);
    msg.msg_namelen = sizeof(daddr);   
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
    ret = sendmsg(sock_fd, &msg, 0);
    if(0 >= ret)
	{
		perror("sendto kernel error\n");
		ret = -5;
		goto CleanUp;
	}
    memset(nlh,0,NLMSG_SPACE(MAX_PAYLOAD));
    recvmsg(sock_fd, &msg, 0);
    if(0 >= ret)
	{
		perror("recvfrom kernel error\n");
		ret = -6;
		goto CleanUp;
	}
    printf("Received message: %s\n",(char *) NLMSG_DATA(nlh));
    ret = 0;
	
CleanUp:
	close(sock_fd);
	free(nlh);
	return ret;
}

內(nèi)核程序-kernel_netlink_demo.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/netlink.h>
#include <net/sock.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/types.h>
#include <linux/sched.h>

#define NETLINK_TEST 30
#define MSG_LEN      125
#define USER_PORT    100

MODULE_LICENSE("GPL");
MODULE_AUTHOR("lixuezahng");
MODULE_DESCRIPTION("netlink example");


struct sock *nl_sk = NULL;
struct net init_net;

static int netlink_send_msg(char *send_buf, size_t len, long pid)
{
	struct sk_buff *psk_buff_t;
	struct nlmsghdr *pnlmsghdr_t;
	
	int ret;
	
	psk_buff_t = nlmsg_new(len, GFP_ATOMIC); //創(chuàng)建sk_buff空間
	if(NULL == psk_buff_t)
	{
		printk("netlink alloc failure\n");
		return -1;
	}
	
	/* 設(shè)置netlink消息頭 */
	pnlmsghdr_t = nlmsg_put(psk_buff_t, 0, 0, pid, len, 0);
	if(NULL == pnlmsghdr_t)
	{
		printk("nlmsg_put failure\n");
		nlmsg_free(psk_buff_t);        //針對nlmsg_new申請空間的釋放問題,若put失敗需要手動釋放,若put成功netlink_unicast發(fā)送后內(nèi)核會自己處理
		return -2;
	}
	
	memcpy(NLMSG_DATA(pnlmsghdr_t), send_buf, len);
	
	/*
		內(nèi)核發(fā)送單播消息
		extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 portid, int nonblock);
		ssk: netlink socket 
		skb: skb buff 指針 
		portid:通信的端口號 
		nonblock:表示該函數(shù)是否為非阻塞,如果為1,該函數(shù)將在沒有接收緩存可利用時立即返回,而如果為 0,該函數(shù)在沒有接收緩存可利用 定時睡眠
		
		內(nèi)核發(fā)送多播消息
		extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 portid, __u32 group, gfp_t allocation);
		ssk: 同上(對應(yīng) netlink_kernel_create 返回值)、 
		skb: 內(nèi)核 skb buff 
		portid:端口id 
		group: 是所有目標(biāo)多播組對應(yīng)掩碼的"OR"操作的。 
		allocation: 指定內(nèi)核內(nèi)存分配方式,通常 GFP_ATOMIC 用于中斷上下文,而 GFP_KERNEL 用于其他場合。這個參數(shù)的存在是因?yàn)樵?API 可能需要分配一個或多個緩沖區(qū)來對多播消息進(jìn)行 clone。 
	*/
	ret = netlink_unicast(nl_sk, psk_buff_t, pid, MSG_DONTWAIT);
	
	return ret;
}
	
static void netlink_rcv_msg(struct sk_buff *psk_buff_t)
{
	struct nlmsghdr *pnlmsghdr_t = NULL;
	char *umsg = NULL;
	char *kmsg = "hello users!!!";
	
	if(psk_buff_t->len >= nlmsg_total_size(0))
	{
		pnlmsghdr_t = nlmsg_hdr(psk_buff_t);
		umsg = NLMSG_DATA(pnlmsghdr_t);
		if(umsg)
		{
			printk("kernel recv from user: %s\n", umsg);
			netlink_send_msg(kmsg, strlen(kmsg), pnlmsghdr_t->nlmsg_pid);
		}
	}
}

struct netlink_kernel_cfg cfg = {
		.input = netlink_rcv_msg, /* set recv callback */
};


static int __init nlmoudle_init(void)
{
	printk(KERN_ALERT "my netlink_kernel in\n");
	
	/*
		static inline struct sock * netlink_kernel_create(struct net *net, int unit, struct netlink_kernel_cfg *cfg) 
		net:指向所在的網(wǎng)絡(luò)命名空間, 默認(rèn)傳入的是 &init_net (不需要定義);  定義在 net_namespace.c(extern struct net init_net); 
		unit:netlink協(xié)議類型
		cfg:cfg 存放的是 netlink 內(nèi)核配置參數(shù)
		struct netlink_kernel_cfg { 
			unsigned int    groups; 
			unsigned int    flags; 
			void        	(*input)(struct sk_buff *skb); // input 回調(diào)函數(shù)
			struct mutex    *cb_mutex; 
			void        (*bind)(int group); 
			bool        (*compare)(struct net *net, struct sock *sk); 
}; 
	*/
	nl_sk = (struct sock *)netlink_kernel_create(&init_net, NETLINK_TEST, &cfg);
	return 0;
}

static void __exit nlmoudle_exit(void)
{
	printk(KERN_ALERT "my netlink_kernel out\n");
	netlink_kernel_release(nl_sk);
}

module_init(nlmoudle_init);
module_exit(nlmoudle_exit);

makefile

KERNEL_DIR := /XX/XX/linux-3.10 #指定內(nèi)核的路徑
CURRENT_PATH := $(shell pwd)    #當(dāng)前路徑
obj-m += kernel_netlink_demo.o    #編譯kernel_ioctl_demo.c生成.ko文件
 
build:netlink_module              #總目標(biāo)
 
netlink_module:
	$(MAKE) -C $(KERNEL_DIR) ARCH=XXX CROSS_COMPILE=XXX M=$(CURRENT_PATH) modules
    #-C [CPATH]表示make要跳轉(zhuǎn)到CPATH路徑執(zhí)行make
    #-M [MPATH]表示執(zhí)行完CPATH路徑下的make后再回到MPATH繼續(xù)執(zhí)行剩下的
    #ARCH 指定處理器架構(gòu)
    #CROSS_COMPILE 指定交叉編譯器
 
clean:
	$(MAKE) -C $(KERNEL_DIR) M=$(CURRENT_PATH) clean

sendmsg實(shí)例

/*************************************************************************
 * @description             : nl_send_msg 函數(shù),通過netlink發(fā)送數(shù)據(jù)到內(nèi)核
 * @param -sock_fd          : sock描述符
 * @param -dst_addr         : netlink目的地址
 * @param -message          : 發(fā)送的數(shù)據(jù)
 * @param -len              :發(fā)送數(shù)據(jù)的長度
 * @return                  : 失敗返回 -1,成功返回0
 *************************************************************************/


static int nl_send_msg(int sock_fd, struct sockaddr_nl *dst_addr, char *message, int len)
{
	struct nlmsghdr *nlh = NULL;
	struct iovec iov;
	struct msghdr msg;

	if( !len || !message)
	{
		printf("message is empty or len is zero\n");
		return -1;
	}
	/* 1、構(gòu)建nlh */
	if(NULL == (nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(len))))
	{
		printf("nlh malloc failed\n");
		return -1;
	}

	nlh->nlmsg_len 		= NLMSG_SPACE(len);
	nlh->nlmsg_pid 		= getpid();
	nlh->nlmsg_flags 	= 0;
	memcpy(NLMSG_DATA(nlh), message, len);

	/* 2、構(gòu)建iov */

	iov.iov_base = (void *)nlh;
	iov.iov_len = nlh->nlmsg_len;

	/* 3、構(gòu)建msg */
	memset(&msg, 0, sizeof(struct msghdr));
	msg.msg_name = (void *)dst_addr;
	msg.msg_namelen = sizeof(struct sockaddr_nl);
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;

	/* 4、發(fā)送消息 */
	if(0 > sendmsg(sock_fd, &msg, 0))
	{
		printf("sendmsg failed\n");
		free(nlh);
		return -1;
	}

	free(nlh);

	return 0;
}

/*************************************************************************
 * @description             : nl_recv_msg 函數(shù),接收從內(nèi)核發(fā)送的數(shù)據(jù)
 * @param -sock_fd          : sock描述符
 * @param -dst_addr         : netlink源地址
 * @param -message          : 接收到的數(shù)據(jù)
 * @param -len              :接收到數(shù)據(jù)的長度
 * @return                  : 失敗返回 -1,成功返回0
 *************************************************************************/

static int nl_recv_msg(int sock_fd, struct sockaddr_nl *src_addr, char *message, int len)
{
	struct nlmsghdr *nlh = NULL;
	struct iovec iov;
	struct msghdr msg;

	if( !len || !message)
	{
		printf("message is empty or len is zero\n");
		return -1;
	}

	/* 1、構(gòu)建nlh */
	if(NULL == (nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(RESCVPLAYLOAD))))
	{
		printf("recv nlh malloc failed\n");
		return -1;
	}

	/* 2、構(gòu)建ivo */
	iov.iov_base = (void *)nlh;
	iov.iov_len = NLMSG_SPACE(RESCVPLAYLOAD);

	/* 3、構(gòu)建msg */
	memset(src_addr, 0, sizeof(struct sockaddr_nl));
	memset(&msg, 0, sizeof(struct msghdr));
	msg.msg_name = (void *)src_addr;
	msg.msg_namelen = sizeof(struct sockaddr_nl);
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;

	/* 4、接受信息 */
	if(0 > recvmsg(sock_fd, &msg, 0))
	{
		printf("recv_message failed\n");
		free(nlh);
		return -1;
	}

	memcpy(message, (unsigned char *)NLMSG_DATA(nlh), nlh->nlmsg_len - NLMSG_SPACE(0));

	free(nlh);
	return 0;
}

到了這里,關(guān)于內(nèi)核與用戶空間的通信實(shí)現(xiàn)—netlink的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Linux字符設(shè)備驅(qū)動(設(shè)備文件,用戶空間與內(nèi)核空間進(jìn)行數(shù)據(jù)交互,ioctl接口)

    Linux字符設(shè)備驅(qū)動(設(shè)備文件,用戶空間與內(nèi)核空間進(jìn)行數(shù)據(jù)交互,ioctl接口)

    在Linux系統(tǒng)中“一切皆文件”,上一篇講述了cdev結(jié)構(gòu)體就描述了一個字符設(shè)備驅(qū)動,主要包括設(shè)備號和操作函數(shù)集合。但是要怎么操作這個驅(qū)動呢?例如,使用open()該打開誰,read()該從哪讀取數(shù)據(jù)等等。所以就需要創(chuàng)建一個設(shè)備文件來代表設(shè)備驅(qū)動。 應(yīng)用程序要操縱外部硬件

    2024年02月12日
    瀏覽(27)
  • 內(nèi)核和用戶空間中的TID,GID, PID,uid

    內(nèi)核和用戶空間中的TID,GID, PID,uid

    要獲取關(guān)于eBPF中的進(jìn)程信息,可以使用以下函數(shù): bpf_get_current_pid_tgid()、 bpf_get_current_uid_gid()、 bpf_get_current_comm(char *buf, int size_of_buf)。 當(dāng)程序被綁定到對某個內(nèi)核函數(shù)調(diào)用時,就可以使用它們。UID/GID應(yīng)該比較明確,但對于那些以前沒有接觸過內(nèi)核操作細(xì)節(jié)的人來說,還是需要

    2024年02月07日
    瀏覽(20)
  • 【linux驅(qū)動】用戶空間程序與內(nèi)核模塊交互-- IOCTL和Netlink

    【linux驅(qū)動】用戶空間程序與內(nèi)核模塊交互-- IOCTL和Netlink

    創(chuàng)建自定義的IOCTL(輸入/輸出控制)或Netlink命令以便用戶空間程序與內(nèi)核模塊交互涉及幾個步驟。這里將分別介紹這兩種方法。 1. 定義IOCTL命令 在內(nèi)核模塊中,需要使用宏定義你的IOCTL命令。通常情況下,IOCTL命令包括了一個命令編號、請求類型的方向(讀/寫/兩者)以及數(shù)

    2024年01月20日
    瀏覽(26)
  • Windows驅(qū)動(用戶層R3與內(nèi)核層R0通信)

    Windows驅(qū)動(用戶層R3與內(nèi)核層R0通信)

    內(nèi)存空間分為用戶層和系統(tǒng)層,普通的應(yīng)用程序只能運(yùn)行在用戶層,為了可以操作系統(tǒng)層的內(nèi)存 所以引入了驅(qū)動程序,有了驅(qū)動就可以通過用戶層來操作系統(tǒng)層的內(nèi)存及函數(shù),所以驅(qū)動就是應(yīng)用層和系統(tǒng)層之間的一個橋梁 在應(yīng)用層通過創(chuàng)建符號鏈接,自動產(chǎn)生驅(qū)動層的IRP事

    2024年02月14日
    瀏覽(18)
  • 51內(nèi)核單片機(jī)實(shí)現(xiàn)Bootloader跳轉(zhuǎn)到用戶程序,要求兩個程序都要支持中斷

    51內(nèi)核單片機(jī)實(shí)現(xiàn)Bootloader跳轉(zhuǎn)到用戶程序,要求兩個程序都要支持中斷

    本文使用的單片機(jī)為笙科的A9129F6,F(xiàn)lash大小為64KB,SRAM大小為8KB。 Flash空間規(guī)劃如下。 起始地址 結(jié)束地址 用途 0x0000 0x3fff Bootloader 程序 0x4000 0xefff 用戶程序( APP 程序) 0xf000 0xffff 存放設(shè)備 配置信息 程序間跳轉(zhuǎn)實(shí)現(xiàn)起來很簡單,只需要使用函數(shù)指針就行了。 但是難點(diǎn)在于

    2024年02月16日
    瀏覽(24)
  • java 多用戶即時通信系統(tǒng)的實(shí)現(xiàn) 萬字詳解

    java 多用戶即時通信系統(tǒng)的實(shí)現(xiàn) 萬字詳解

    目錄 前言 一、拾枝雜談 ? ? ? ? 1.項(xiàng)目開發(fā)大體流程 :? ? ? ? ? 2.多用戶即時通信系統(tǒng)分析 :? ? ? ? ? ? ? ? ? 1° 需求分析 ? ? ? ? ? ? ? ? 2° 整體分析 二、用戶登錄 ? ? ? ? 1.準(zhǔn)備工作?:? ????????2.客戶端 :? ????????????????1° 菜單界面 ? ? ? ? ? ? ?

    2024年02月06日
    瀏覽(17)
  • 基于BGP+OSPF+路由策略實(shí)現(xiàn)合理穿過運(yùn)營商,實(shí)現(xiàn)跨域內(nèi)網(wǎng)用戶之間的通信

    基于BGP+OSPF+路由策略實(shí)現(xiàn)合理穿過運(yùn)營商,實(shí)現(xiàn)跨域內(nèi)網(wǎng)用戶之間的通信

    實(shí)驗(yàn)結(jié)構(gòu)拓?fù)鋱D: ?實(shí)驗(yàn)要求: 實(shí)驗(yàn)過程: 1:ip地址規(guī)劃,具體劃分請見拓?fù)浣Y(jié)構(gòu)圖所示? 2:各AS域內(nèi)啟用OSPF協(xié)議。實(shí)現(xiàn)域內(nèi)網(wǎng)絡(luò)聯(lián)通,宣告環(huán)回,為EBGP、IBGP建鄰做準(zhǔn)備 3:不同域之間建立EBGP對等體關(guān)系、AS域內(nèi)建立IBGP對等體關(guān)系 4:在AS1、AS4上宣告內(nèi)網(wǎng)網(wǎng)段,實(shí)現(xiàn)控制層面可達(dá),

    2024年01月19日
    瀏覽(17)
  • Linux內(nèi)核源碼分析 (B.2)虛擬地址空間布局架構(gòu)

    Linux內(nèi)核源碼分析 (B.2)虛擬地址空間布局架構(gòu)

    Linux內(nèi)核只是操作系統(tǒng)當(dāng)中的一部分,對下管理系統(tǒng)所有硬件設(shè)備,對上通過系統(tǒng)調(diào)用向 Library Routine 或其他應(yīng)用程序提供API接口。 內(nèi)存管理可以通過以下三個維度進(jìn)行介紹: 用戶空間 相當(dāng)于應(yīng)用程序使用 malloc() 申請內(nèi)存,通過 free() 釋放內(nèi)存。 malloc() / free() 是 glibc 庫的內(nèi)

    2024年02月09日
    瀏覽(41)
  • 內(nèi)核態(tài)、用戶態(tài)概念

    MTU(Maximum Transmission Unit,最大傳輸單元)是指在網(wǎng)絡(luò)中傳輸?shù)臄?shù)據(jù)包的最大長度限制,它是一個重要的網(wǎng)絡(luò)參數(shù),影響著網(wǎng)絡(luò)的可靠性、穩(wěn)定性和性能。在TCP/IP協(xié)議棧中,MTU涉及到內(nèi)核態(tài)和用戶態(tài)兩個方面。 在內(nèi)核態(tài)中,網(wǎng)絡(luò)設(shè)備的MTU由網(wǎng)絡(luò)驅(qū)動程序設(shè)置并保存在內(nèi)核中。

    2024年02月16日
    瀏覽(16)
  • 詳解內(nèi)核態(tài)與用戶態(tài)

    詳解內(nèi)核態(tài)與用戶態(tài)

    內(nèi)核態(tài)和用戶態(tài)是操作系統(tǒng)中的兩種不同的運(yùn)行狀態(tài),它們的區(qū)別如下: 權(quán)限不同:內(nèi)核態(tài)是操作系統(tǒng)擁有最高權(quán)限的運(yùn)行狀態(tài),可以訪問系統(tǒng)的所有資源,而用戶態(tài)只能訪問受限的資源。 系統(tǒng)調(diào)用:在用戶態(tài)下,應(yīng)用程序需要通過系統(tǒng)調(diào)用來請求操作系統(tǒng)提供服務(wù),而在

    2024年02月13日
    瀏覽(22)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包