linux下用户程序同内核通信详解(netlink机制)

2019-10-10 16:14:31王旭

2.Makefile

KERNEL_MODULES := netlink 
 
export MODULES_ROOT_DIR := $(shell pwd) 
export MODULES_BUILD_DIR := $(MODULES_ROOT_DIR)/build 
export KDIR := /lib/modules/$(shell uname -r)/build #这行是为了取出系统下内核的目录(ubuntu) 
 
all: init modules romfs 
 
init: 
 mkdir -p $(MODULES_BUILD_DIR) 
 
modules:$(patsubst %, _dir_%, $(KERNEL_MODULES)) 
 
$(patsubst %, _dir_%, $(KERNEL_MODULES)): 
 @echo 
 @echo Building $(patsubst _dir_%, %, $@) 
 $(MAKE) -C $(patsubst _dir_%, %, $@) all 
 
 
romfs: $(patsubst %, _romfs_%, $(KERNEL_MODULES)) 
$(patsubst %, _romfs_%, $(KERNEL_MODULES)): 
 $(MAKE) -C $(patsubst _romfs_%, %, $@) romfs 
 
 
clean: $(patsubst %, _clean_%, $(KERNEL_MODULES)) 
 $(RM) $(BUILD_DIR) 
$(patsubst %, _clean_%, $(KERNEL_MODULES)): 
 @echo 
 @echo Cleaning $(patsubst _dir_%, %, $@) 
 $(MAKE) -C $(patsubst _clean_%, %, $@) clean 
 
.PHONY: 

3. ./netlink/netlink.c

/* 
 * netlink.c 
 * 
 * Created on: 2014 *  Author: cr 
 */ 
 
#include <linux/init.h> 
#include <linux/module.h> 
#include <linux/kernel.h> 
#include <linux/skbuff.h> 
#include <linux/ip.h> 
#include <linux/types.h> 
#include <linux/sched.h> 
#include <linux/netlink.h> 
#include <net/sock.h> 
#include "usrlink.h" 
 
MODULE_LICENSE("Dual BSD/GPL"); 
MODULE_AUTHOR("MDAXIA"); 
 
struct sock *netlink_fd; 
 
 
static void netlink_to_user(int dest, void *buf, int len) 
{ 
 struct nlmsghdr *nl; 
 struct sk_buff *skb; 
 int size; 
 
 size = NLMSG_SPACE(len); 
 skb = alloc_skb(size, GFP_ATOMIC); 
 if(!skb || !buf) 
 { 
  printk(KERN_ALERT "netlink_to_user skb of buf null!n"); 
  return; 
 } 
 nl = nlmsg_put(skb, 0, 0, 0, NLMSG_SPACE(len) - sizeof(struct nlmsghdr), 0); 
 NETLINK_CB(skb).pid = 0; 
 NETLINK_CB(skb).dst_group = 0; 
 
 memcpy(NLMSG_DATA(nl), buf, len); 
 nl->nlmsg_len = (len > 2) ? (len - 2):len; 
 
 netlink_unicast(netlink_fd, skb, dest, MSG_DONTWAIT); 
 printk(KERN_ALERT "K send packet successn"); 
} 
 
static int process_hello_get(int dest, void *buf, int len) 
{ 
 printk(KERN_ALERT "In process_hello get!n"); 
 memcpy(buf, "I known you !", 13); 
 netlink_to_user(dest, buf, 13); 
 return NET_OK; 
} 
 
static int process_hello_set(int dest, void *buf, int len) 
{ 
 printk(KERN_ALERT "In process_hello set! %sn", (char *)buf); 
 memcpy(buf, "S known you !", 13); 
 netlink_to_user(dest, buf, 13); 
 return NET_OK; 
} 
 
 
static void netlink_process_packet(struct nlmsghdr *nl) 
{ 
 int ret; 
 
 switch(nl->nlmsg_type) 
 { 
 case HELLO_GET: 
  ret = process_hello_get(nl->nlmsg_pid, NLMSG_DATA(nl), nl->nlmsg_len); 
  break; 
 case HELLO_SET: 
  ret = process_hello_set(nl->nlmsg_pid, NLMSG_DATA(nl), nl->nlmsg_len); 
  break; 
 default:break; 
 } 
} 
 
static void netlink_recv_packet(struct sk_buff *__skb) 
{ 
 struct sk_buff *skb; 
 struct nlmsghdr *nlhdr; 
 
 skb = skb_get(__skb); 
 if(skb->len >= sizeof(struct nlmsghdr)) 
 { 
  nlhdr = (struct nlmsghdr *)skb->data; 
  if(nlhdr->nlmsg_len >= sizeof(struct nlmsghdr) && 
    __skb->len >= nlhdr->nlmsg_len) 
  { 
   netlink_process_packet(nlhdr); 
  } 
 } 
 else 
  printk(KERN_ALERT "Kernel receive msg length error!n"); 
} 
 
static int __init netlink_init(void) 
{ 
 netlink_fd = netlink_kernel_create(&init_net, USER_NETLINK_CMD, 0, netlink_recv_packet, NULL, THIS_MODULE); 
 if(NULL == netlink_fd) 
 { 
  printk(KERN_ALERT "Init netlink!n"); 
  return -1; 
 } 
 printk(KERN_ALERT "Init netlink success!n"); 
 return 0; 
} 
 
static void __exit netlink_exit(void) 
{ 
 netlink_kernel_release(netlink_fd); 
 printk(KERN_ALERT "Exit netlink!n"); 
} 
 
module_init(netlink_init); 
module_exit(netlink_exit);