linux 用户态和内核通信之Netlink

http://www.linuxidc.com/Linux/2011-07/39085p2.htm

之前参考这篇帖子练习了一下netlink,当时记得可以正常调试成功,今天在自己笔记本上ubuntu 12.04 上调试了一下,结果一直出现kernel panic, 调试了一下发现应该是出现在kernel 向用户空间发送消息的流程中。至今没调试成功,记录一下吧,抽时间在调试一下:

用户空间:

/*
 * netlink_user.c
 */
#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 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;
}
内核空间:

/*
 * netlink_kernel.c
 */
#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>

#define NETLINK_TEST 25
#define MAX_MSGSIZE 1024

int stringlength(char *s);
void sendnlmsg(char* message);

int pid;
int err;
struct sock *nl_sk = NULL;
int flag = 0;

void sendnlmsg(char* message)
{
    struct sk_buff *skb_1;
    struct nlmsghdr *nlh;
    int len = NLMSG_SPACE(MAX_MSGSIZE);
    int slen = 0;
    
    if(!message || !nl_sk)
    {
        return ;
    }
    
    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;

	message[slen]= '\0';
	memcpy(NLMSG_DATA(nlh),message,slen+1);
	printk("my_net_link:send message '%s'.\n",(char *)NLMSG_DATA(nlh));
    netlink_unicast(nl_sk,skb_1,pid,MSG_DONTWAIT);

}

int stringlength(char *s)
{
    int slen = 0;

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

    return slen;
}

void nl_data_ready(struct sk_buff *__skb)
 {	
	struct sk_buff *skb;
	struct nlmsghdr *nlh;
	char str[100];
	struct completion cmpl;
	int i=10;
	
	printk(KERN_ALERT "entering nl_data_ready\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;
		
		printk(KERN_ALERT "pid is: %d\n",pid);
		/*while(i--)
		{
			init_completion(&cmpl);
			wait_for_completion_timeout(&cmpl,3 * HZ);
			sendnlmsg("I am from kernel!");
		}*/
		
		//NETLINK_CB(skb).groups = 0; /* not in mcast group */
		NETLINK_CB(skb).pid = 0;      /* from kernel */
		//NETLINK_CB(skb).dst_pid = pid;
		NETLINK_CB(skb).dst_group = 0;  /* unicast */
	    //netlink_unicast(nl_sk,skb,pid,MSG_DONTWAIT);

		flag = 1;
		kfree_skb(skb);
    }

 }

// Initialize netlink

int netlink_init(void)
{


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

    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;
}

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("xxxxxxx");
MODULE_LICENSE("GPL");
Makefile:

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值