openwrt系统实现netlink双向通信

无线AP(openwrt系统)中实现netlink双向通信

最近在做一个关于车联网项目,需要用户态和内核态进行通信,于是在网上搜索相关资料,但网上大都是讲解如何实现netlink以及netlink原理,并未涉及如何在openwrt系统中添加netlink模块。故在这里讲解如何在openwrt系统中添加netlink模块。

内核态代码

**1、**初始化netlink

首先需要编译好openwrt系统(至于如何编译可参考网上资料,这里不再赘述),

在进入这里插入图片描述

进入上图所示目录,找到init.c文件,在int __init ath9k_init函数添加下面注释代码

static int __init ath9k_init(void)
{
	int error;

	error = ath_ahb_init();
	if (error < 0) {
		error = -ENODEV;
		goto err_out;
	}

	error = ath_pci_init();
	if (error < 0) {
		pr_err("No PCI devices found, driver not installed\n");
		error = -ENODEV;
		goto err_ahb_exit;
	}

	//jeff-2019.5.9
	netlink_init();
	//end
	return 0;

 err_ahb_exit:
	ath_ahb_exit();
 err_out:
	return error;
}
module_init(ath9k_init);

在ath9k_exit函数中添加下面注释代码块

static void __exit ath9k_exit(void)
{
	is_ath9k_unloaded = true;

	//jeff-2019.5.9
	netlink_exit();
	//end
	ath_ahb_exit();
	ath_pci_exit();
	pr_info("%s: Driver unloaded\n", dev_info);
}
module_exit(ath9k_exit);

在ath9k.h文件中添加下面注释代码

static inline int ath_ahb_init(void) { return 0; };
static inline void ath_ahb_exit(void) {};
#endif
//jeff-2019.5.9
int netlink_init(void);
int stringlength(char *s);
void send_netlink_data(char *message);
void recv_netlink_data(struct sk_buff *__skb);
void netlink_exit(void);
//end

#endif /* ATH9K_H */

2添加netlink收发模块
在上面目录中,找到main.c文件,添加下面头文件

//jeff-2019.5.9
#include 
#include 
#include 
#include 
#include 
#include 
#include  
//end 

在main.c中添加下面代码

//jeff-2019.5.9
#define NETLINK_TEST 25
#define MAX_MSGSIZE 1024

extern struct net init_net;

int pid;
int err;
struct sock *nl_sk = NULL;
int flag = 0;
char str[100];

int stringlength(char *s)
{
	int slen = 0;
	for(; *s; s++)
	{
		slen++;
	}
   	return slen;
}

void send_netlink_data(char *message)
{
	struct sk_buff *skb_1;
	struct nlmsghdr *nlh;
	int len = NLMSG_SPACE(MAX_MSGSIZE);
	int slen = 0;
 
	skb_1 = alloc_skb(len,GFP_KERNEL);
	if(!skb_1)
	{
		printk(KERN_ERR "my_net_link:alloc_skb_1 error\n");
	}
	slen = stringlength(message);
	nlh = nlmsg_put(skb_1,0,0,0,MAX_MSGSIZE,0);
 
	//NETLINK_CB(skb_1).pid = 0;
	NETLINK_CB(skb_1).dst_group = 0;
 
	memcpy(NLMSG_DATA(nlh),message,slen+1);
 
	printk("my_net_link:send = %d, message '%s'.\n",slen,(char *)NLMSG_DATA(nlh));
 
	netlink_unicast(nl_sk,skb_1,pid,MSG_DONTWAIT);
}
void recv_netlink_data(struct sk_buff *__skb)
{
	struct sk_buff *skb;
	struct nlmsghdr *nlh;
	//struct completion cmpl;
	int i=10;
	printk("net_link: data is ready to read.\n");
	skb = skb_get (__skb);
	if(skb->len >= NLMSG_SPACE(0))
	{
		nlh = nlmsg_hdr(skb);
		memcpy(str, NLMSG_DATA(nlh), sizeof(str));
		printk("Message received:%s\n",str) ;
		pid = nlh->nlmsg_pid;
		while(i--)
		{
			//init_completion(&cmpl);
			//wait_for_completion_timeout(&cmpl,1 * HZ);
			send_netlink_data("From kernel messages!");
		}
		flag = 1;
		kfree_skb(skb);
	}
}
struct netlink_kernel_cfg cfg = { 
	.input  = recv_netlink_data, /* set recv callback */
};  

// Initialize netlink
int netlink_init(void)
{
	nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST,&cfg);
	if(!nl_sk)
	{
		printk(KERN_ERR "my_net_link: create netlink socket error.\n");
		return 1;
	}
	printk("my_net_link_3: create netlink socket ok.\n");
	return 0;
}
 void netlink_exit(void)
{
	if(nl_sk != NULL)
	{
		sock_release(nl_sk->sk_socket);
	}
 
    printk("my_net_link: self module exited\n");
}

//end

网上关于实现netlink机制的代码很多,故这里不对代码进行分析,读者可自行百度查找相关解释。
修改完内核代码后,重新编译openwrt系统,进入openwrt目录输入

sudo make V=99

用户态代码
命名为user_sent.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define NETLINK_TEST 25
#define MAX_PAYLOAD 1024 // maximum payload size

int main(int argc, char* argv[])
{
    int state;
    struct sockaddr_nl src_addr, dest_addr;
    struct nlmsghdr *nlh = NULL;
    struct iovec iov;
    struct msghdr msg;
    int sock_fd, retval;
    int state_smg = 0;
    // Create a socket

    sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);
    if(sock_fd == -1){
        printf("error getting socket: %s", strerror(errno));
        return -1;
    }

    // To prepare binding

    memset(&msg,0,sizeof(msg));
    memset(&src_addr, 0, sizeof(src_addr));
    src_addr.nl_family = AF_NETLINK;
    src_addr.nl_pid = getpid(); // self pid

    src_addr.nl_groups = 0; // multi cast


    retval = bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));
    if(retval < 0){
        printf("bind failed: %s", strerror(errno));
        close(sock_fd);
        return -1;
    }

    // To prepare recvmsg

    nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
    if(!nlh){
        printf("malloc nlmsghdr error!\n");
        close(sock_fd);
        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;

    nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
    nlh->nlmsg_pid = getpid();
    nlh->nlmsg_flags = 0;
    strcpy(NLMSG_DATA(nlh),"Hello you!");

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

    memset(&msg, 0, sizeof(msg));
   
    msg.msg_name = (void *)&dest_addr;
    msg.msg_namelen = sizeof(dest_addr);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    printf("state_smg\n");
    state_smg = sendmsg(sock_fd,&msg,0);

    if(state_smg == -1)
    {
        printf("get error sendmsg = %s\n",strerror(errno));
    }

    memset(nlh,0,NLMSG_SPACE(MAX_PAYLOAD));
    printf("waiting received!\n");
    // Read message from kernel

    while(1){
        printf("In while recvmsg\n");
        state = recvmsg(sock_fd, &msg, 0);
        if(state<0)
        {
            printf("state<1");
        }
        printf("In while\n");
        printf("Received message: %s\n",(char *) NLMSG_DATA(nlh));
    }

    close(sock_fd);

    return 0;
}

Makefile

AKEFLAGS += --no-print-directory

PREFIX ?= /usr
SBINDIR ?= $(PREFIX)/sbin
MANDIR ?= $(PREFIX)/share/man
PKG_CONFIG ?= pkg-config

MKDIR ?= mkdir -p
INSTALL ?= install
CC ?= "gcc"

CFLAGS ?= -MMD -O2 -g
CFLAGS += -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common \
		  -DCONFIG_DRIVER_NL80211 -DLIBEVENT2_MGMT_FRAME 

LIBS += -levent -lnl-tiny -ljson-c -lpcap -lpthread

OBJS += ./user_sent.o


-include $(OBJS:%.o=%.d)

all: netlink

%.o: %.c $(DEPS)
	$(CC) -c -o $@ $< $(CFLAGS)

netlink: $(OBJS)
	$(CC) -o $@ $^ $(LDFLAGS) $(LIBS)

clean:
	rm -f *.o netlink

.PHONY : clean

为生成ipk文件的Makefile

include $(TOPDIR)/rules.mk

PKG_NAME:=netlink
PKG_RELEASE:=1.0.0

PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)

include $(INCLUDE_DIR)/package.mk

define Package/netlink
	
	CATEGORY:=My Packet
	TITLE:=netlink
	DEPENDS:= +libevent2 +libnl-tiny +libjson-c +libpcap +libpthread
endef

TARGET_CPPFLAGS:= \
	-I$(STAGING_DIR)/usr/include/json-c \
	-I$(STAGING_DIR)/usr/include/libnl-tiny \
	$(TARGET_CPPFLAGS) \
	-DCONFIG_LIBNL20 \
	-D_GNU_SOURCE

# Uncomment portion below for Kamikaze and delete DESCRIPTION variable above
define Package/netlink/description
	802.11 wireless access controller
endef

define Build/Prepare
	mkdir -p $(PKG_BUILD_DIR)
	$(CP) ./src/* $(PKG_BUILD_DIR)/
endef

define Package/netlink/install
	$(INSTALL_DIR) $(1)/bin
	$(INSTALL_BIN) $(PKG_BUILD_DIR)/netlink $(1)/bin/
endef

$(eval $(call BuildPackage,netlink))


至于如何在openwrt中生成ipk文件,网上有若干资料,这里不再赘述。

最后将生成的openwrt固件和ipk文件刷进AP中。

3、测试结果
openwrt系统实现netlink双向通信_第1张图片
从上图可以看到在AP中实现了从用户态和内核态的双向通信。
以上内容仅供参考,主要作为自己留存。

你可能感兴趣的:(openwrt系统实现netlink双向通信)