最近在做一个关于车联网项目,需要用户态和内核态进行通信,于是在网上搜索相关资料,但网上大都是讲解如何实现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中。