2014-05-25 161 views
0

我試過this program。該程序向內核發送「hello」,內核再次向用戶空間回覆「hello」一次。Netlink給內核恐慌

我的要求:用戶必須發送「你好」,並且必須每2秒接收一次消息。

我試過了。

用戶應用:添加loopfor發送和接收

#define NETLINK_USER 31  
#define MAX_PAYLOAD 1024 /* maximum payload size*/ 

struct sockaddr_nl src_addr, dest_addr; 
struct nlmsghdr *nlh = NULL; 
struct iovec iov; 
int sock_fd; 
struct msghdr msg; 

int main() 
{ 
    sock_fd=socket(PF_NETLINK, SOCK_RAW, NETLINK_USER); 
    if(sock_fd<0) 
     return -1; 

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

    bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr)); 

    memset(&dest_addr, 0, sizeof(dest_addr)); 
    memset(&dest_addr, 0, sizeof(dest_addr)); 
    dest_addr.nl_family = AF_NETLINK; 
    dest_addr.nl_pid = 0; /* For Linux Kernel */ 
    dest_addr.nl_groups = 0; /* unicast */ 

    nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD)); 
    memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD)); 
    nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD); 
    nlh->nlmsg_pid = getpid(); 
    nlh->nlmsg_flags = 0; 

    strcpy(NLMSG_DATA(nlh), "Hello"); 

    iov.iov_base = (void *)nlh; 
    iov.iov_len = nlh->nlmsg_len; 
    msg.msg_name = (void *)&dest_addr; 
    msg.msg_namelen = sizeof(dest_addr); 
    msg.msg_iov = &iov; 
    msg.msg_iovlen = 1; 
    while(1) {   // <--- loop here. only works once. 
     sleep(2); 
     printf("Sending message to kernel\n"); 
     sendmsg(sock_fd,&msg,0); 

     recvmsg(sock_fd, &msg, 0); 
     printf("Received message payload: %s\n", (char *)NLMSG_DATA(nlh)); 
    } 

    close(sock_fd); 
} 

內核模塊:沒有改變任何東西。

#define NETLINK_USER 31 
struct sock *nl_sk = NULL; 

static void hello_nl_recv_msg(struct sk_buff *skb) 
{ 
    struct nlmsghdr *nlh; 
    int pid; 
    struct sk_buff *skb_out; 
    int msg_size; 
    char *msg="Hello from kernel"; 
    int res; 

    printk(KERN_INFO "Entering: %s\n", __FUNCTION__); 

    msg_size=strlen(msg); 

    nlh=(struct nlmsghdr*)skb->data; 
    printk(KERN_INFO "Netlink received msg payload:%s\n",(char*)nlmsg_data(nlh)); 
    pid = nlh->nlmsg_pid; /*pid of sending process */ 

    skb_out = nlmsg_new(msg_size,0); 

    if(!skb_out) 
    { 
     printk(KERN_ERR "Failed to allocate new skb\n"); 
     return; 
    } 
    nlh=nlmsg_put(skb_out,0,0,NLMSG_DONE,msg_size,0); 
    NETLINK_CB(skb_out).dst_group = 0; /* not in mcast group */ 
    strncpy(nlmsg_data(nlh),msg,msg_size); 

    res=nlmsg_unicast(nl_sk,skb_out,pid); 

    if(res<0) 
     printk(KERN_INFO "Error while sending bak to user\n"); 
} 

static int __init hello_init(void) 
{ 
    struct netlink_kernel_cfg cfg = { 
     .input = hello_nl_recv_msg 
    }; 

    nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg); 

    printk("Entering: %s\n",__FUNCTION__); 

    if(!nl_sk) 
    {  
     printk(KERN_ALERT "Error creating socket.\n"); 
     return -10; 
    } 
    return 0; 
} 

static void __exit hello_exit(void) 
{ 
    printk(KERN_INFO "exiting hello module\n"); 
    netlink_kernel_release(nl_sk); 
} 

module_init(hello_init); 
module_exit(hello_exit); 

此代碼僅適用於第一個循環。下一次內核崩潰並在黑屏中發出內核恐慌錯誤。每次我重新啓動。爲什麼它給核心恐慌?我需要修改的地方?我認爲問題在內核模塊中。
內核:3.13.0-24-generic

+0

你運行的是什麼版本的內核? 'uname -a'的輸出在這裏很有用。 –

+0

'3.13.0-24-generic' @JonathonReinhart – SGG

+1

爲什麼'-1'?需要更多信息? – SGG

回答

1

嗯,我認爲問題是在內核模塊。但問題出在用戶模塊中。我工作了3天,以確定這個問題。問題是在

while(1) {   
    sleep(2); 
    printf("Sending message to kernel\n"); 
    sendmsg(sock_fd,&msg,0);  // In 2nd iteration msg value chaged 

    recvmsg(sock_fd, &msg, 0); // <--- msg will update 
    printf("Received message payload: %s\n", (char *)NLMSG_DATA(nlh)); 
} 

此循環只能工作一次。那是真實的。使用recvmsg收到消息後,msg變量被更新,並且我使用該變量再次發送。這是因爲代碼已經過時了,所以(源和目標)都指向相同的指針。

通過寫入sendmsgrecvmsg的不同變量將消除該問題。

int main() 
{ 
    int seq_no = 1; 
    sock_fd=socket(PF_NETLINK, SOCK_RAW, NETLINK_USER); 
    if(sock_fd<0) 
      return -1; 

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

    bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr)); 

    memset(&dest_addr, 0, sizeof(dest_addr)); 
    dest_addr.nl_family = AF_NETLINK; 
    dest_addr.nl_pid = 0; /* For Linux Kernel */ 
    dest_addr.nl_groups = 0; /* unicast */ 

    nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD)); 
    memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD)); 
    nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD); 
    nlh->nlmsg_pid = getpid(); 
    nlh->nlmsg_flags = 0; 

    strcpy(NLMSG_DATA(nlh), "Hello"); 

    iov.iov_base = (void *)nlh; 
    iov.iov_len = nlh->nlmsg_len; 
    msg.msg_name = (void *)&dest_addr; 
    msg.msg_namelen = sizeof(dest_addr); 
    msg.msg_iov = &iov; 
    msg.msg_iovlen = 1; 
              /* receiver parameters */ 
    nlh_in = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD)); 
    iov_in.iov_base = (void *)nlh_in; 
    iov_in.iov_len = nlh->nlmsg_len; 
    msg_in.msg_iov = &iov_in; 
    msg_in.msg_iovlen = 1;     /* end */ 

    while(1) { 
     printf("sending message to kernel\n"); 
     sendmsg(sock_fd,&msg,0); 

     recvmsg(sock_fd, &msg_in, 0); 
     printf("Received message payload: %s\n", (char *)NLMSG_DATA(nlh_in)); 
     sleep(1); 
    } 
    free(nlh); 
    close(sock_fd); 
}