netlink socket實現內核和用戶的通信

先看代碼,內核的:


#include <linux/init.h>   
#include <linux/module.h>   
#include <linux/timer.h> 
#include <linux/time.h>  
#include <linux/types.h>
#include <net/sock.h>
#include <net/netlink.h> //it include linux/netlink.h

#define NETLINK_TEST 17
#define MAX_MSGSIZE 1024

struct sock *nl_sk = NULL;

// Get string's length
int stringlength(char *s)
{
	int slen = 0;

	for(; *s; s++){
        slen++;
    }

	return slen;
}

// Send message by netlink
void sendnlmsg(char *message)  
{
	struct sk_buff *skb;
	struct nlmsghdr *nlh;
	int len = NLMSG_SPACE(MAX_MSGSIZE);
	int slen = 0;
	
	if(!message || !nl_sk){
        return;
    }

	// Allocate a new sk_buffer
	skb = alloc_skb(len, GFP_KERNEL);
	if(!skb){
		printk(KERN_ERR "my_net_link: alloc_skb Error./n");
		return;
	}

	slen = stringlength(message);

    //Initialize the header of netlink message
	nlh = nlmsg_put(skb, 0, 0, 0, MAX_MSGSIZE, 0);

	NETLINK_CB(skb).pid = 0; // from kernel
    NETLINK_CB(skb).dst_group = 1; // multi cast

	message[slen] = '/0';
	memcpy(NLMSG_DATA(nlh), message, slen+1);
    printk("my_net_link: send message '%s'./n", (char *)NLMSG_DATA(nlh));

	//send message by multi cast
    netlink_broadcast(nl_sk, skb, 0, 1, GFP_KERNEL); 
    return;
}

// Initialize netlink
int netlink_init(void)
{
    int i = 10;
    struct completion cmpl;

    nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST, 1, 
                                  NULL, NULL, THIS_MODULE);

	if(!nl_sk){
		printk(KERN_ERR "my_net_link: create netlink socket error./n");
		return 1;
	}

	printk("my_net_link: create netlink socket ok./n");
    while(i--){
        init_completion(&cmpl);
        wait_for_completion_timeout(&cmpl, 3 * HZ);
        sendnlmsg("I am from kernel!");
        
    }

	return 0;
}

static void netlink_exit(void)   
{   
	if(nl_sk != NULL){
    	sock_release(nl_sk->sk_socket);
  	}

	printk("my_net_link: self module exited/n");   
}

module_init(netlink_init);   
module_exit(netlink_exit);   

MODULE_AUTHOR("donglp");   
MODULE_LICENSE("GPL"); 

用戶的:


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

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


int main(int argc, char* argv[])
{
    struct sockaddr_nl src_addr, dest_addr;
    struct nlmsghdr *nlh = NULL;
    struct iovec iov;
    struct msghdr msg;
    int sock_fd, retval;
    
    // Create a socket
    sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_TEST);
    if(sock_fd == -1){
        printf("error getting socket: %s", strerror(errno));
        return -1;
    }
    
    // To prepare binding
    memset(&src_addr, 0, sizeof(src_addr));
    src_addr.nl_family = PF_NETLINK; 
    src_addr.nl_pid = getpid();  // self pid 
    src_addr.nl_groups = 1; // 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(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
    iov.iov_base = (void *)nlh;
    iov.iov_len = NLMSG_SPACE(MAX_PAYLOAD);

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

    // Read message from kernel
    while(1){
        recvmsg(sock_fd, &msg, 0);
        printf("Received message: %s/n", NLMSG_DATA(nlh));
    }

    close(sock_fd);

    return 0;
}

Makefile文件:

obj-m := self.o
KERNELBUILD := /lib/modules/`uname -r`/build
default:
	@echo "  BUILD kmod"
	@make -C $(KERNELBUILD) M=$(shell pwd) modules
	gcc -o u u.c
clean:
	@echo "  CLEAN kmod"
	@rm -rf *.o
	@rm -rf .depend .*.cmd *.ko *.mod.c .tmp_versions *.symvers .*.d

編譯方法:直接make

 

如何看效果:

必須先運行insmod self.ko 

然後在另外一個終端運行./u

 

就能看到效果,關注dmesg信息和./u顯示出來的信息;


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章