2016-04-05 21 views
1

免責事項 - 私はこのカーネルインターフェース(ソケット)を使用しているのは1回目であることを認めなければなりません。ユーザスペースnetlinkソケットは、カーネルスペースから空のメッセージを受け取ります

私は現在、ネットリンクソケットに基づいたカーネルモジュールの設計に取り組んでいます。

私はスターターとしてUbuntu14.04とLinuxカーネル4

を使用しています、私は両方の方向にネットリンクソケットを使用できることを確認したかったです。 私は次のことをするアプリケーションを書いた:

1)ユーザがnetlinkソケット経由でカーネルにメッセージを送る。

2)カーネルは、メッセージを受信すると、 "ABCD"文字列メッセージをワークキューに送ります。

3)「ABCD」メッセージがワークキューによって受信されると、関数は(my_wq_functionという名前の)関数を呼び出し、netlink socketを介してユーザー空間に戻します。

4)ユーザー空間では、私はrecvmsg関数(メッセージが受信されるまでブロッキング)を使用していて、 "ABCD"メッセージを表示しています。

私の問題は、recvmsg関数からの戻り値が20(4ではなく)で、データ自体(つまりNLMSG_DATA)が空であることです。 デバッグ中にメッセージを "ABCD1234"に変更しようとしましたが、戻り値が24バイトになりましたが、データはまだ空です。

また、カーネルからソケットに "ABCD"を送信するまでの私のパス全体がOKであることを確認しました。 ここで間違っていることがわかりません&あなたのお手伝いをさせていただきます。

ありがとうございます、MotiC。私のコードの例を以下に

を見つけることができます:

ユーザ空間のコードを:

printf("netlink receiver thread started...\n"); 

      nlh_rcv = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD)); 
      while(true) //endless loop on netlink socket 
      { 
      memset(nlh_rcv, 0, NLMSG_SPACE(MAX_PAYLOAD)); 
      iov_rcv.iov_base = (void *)nlh_rcv; 

      iov_rcv.iov_len = nlh_rcv->nlmsg_len; 

      msg_rcv.msg_name = (void *)&dest_addr; 
      msg_rcv.msg_namelen = sizeof(dest_addr); 
      msg_rcv.msg_iov = &iov; 
      msg_rcv.msg_iovlen = 1; 

      ret=recvmsg(sock_fd, &msg_rcv, 0); 

      printf("errno=%i bytes=%i message from kernel: %s\n",errno, ret, (char*)NLMSG_DATA(nlh_rcv)); 

      uint8_t mymsg[100]; 
      memcpy(mymsg, NLMSG_DATA(nlh_rcv), 100); 
      printf("message from kernel: %s\n",mymsg); 
    } 

カーネル空間コード:

#include <linux/module.h>  /* Needed by all modules */ 
#include <linux/kernel.h>  /* Needed for KERN_INFO */ 
#include <linux/init.h>   /* Needed for the macros */ 
#include <net/sock.h> 
#include <linux/socket.h> 
#include <linux/net.h> 
#include <asm/types.h> 
#include <linux/netlink.h> 
#include <linux/skbuff.h> 
#include <linux/workqueue.h> 

MODULE_LICENSE("GPL"); 


#include "rf_Kdriver_main.h" 

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

struct sock *nl_sk = NULL; 

struct nlmsghdr *nlh; 
struct nlmsghdr *nlh_out; 

struct sk_buff *skb_out; 

char buf_to_user[100]; 

int pid; 


//------------------------------------------------------------------------------------------------------------------------------ 
struct workqueue_struct *my_wq; 

typedef struct { 
    struct work_struct my_work; 
    uint8_t msg_to_pc[128]; 
    uint8_t msg_len; 
} my_work_t; 

my_work_t *work, *work2; 

//----------------------------------------------------------------------------------------------------------------------------- 
static void my_wq_function(struct work_struct *work) 
{ 
      int res; 
    my_work_t *my_work = (my_work_t *)work; 

    skb_out = nlmsg_new(my_work->msg_len,0); 
    if (!skb_out) 
    { 
      printk("Failed to allocate new skb\n"); 
      return; 
    } 
    nlh_out = nlmsg_put(skb_out, 0, 0, NLMSG_DONE,my_work->msg_len, 0); 
    NETLINK_CB(skb_out).dst_group = 0; 
    memcpy((char*)NLMSG_DATA(nlh_out), my_work->msg_to_pc , my_work->msg_len); 

    printk("dequeue message to pc=%s len=%i\n", (char*)NLMSG_DATA(nlh_out), (int)strlen((char*)NLMSG_DATA(nlh_out))); 

    res = nlmsg_unicast(nl_sk, skb_out, pid); 

    if (res<0) 
      printk("Failed to send message from kernel to user\n"); 


    kfree((void *)work); 

    return; 
} 
//----------------------------------------------------------------------------------------------------------------------------- 
int send_up_msg_to_workque(uint8_t msg_to_pc[], uint8_t msg_len) 
{ 
    int ret=0; 

    work = (my_work_t *)kmalloc(sizeof(my_work_t), GFP_KERNEL); 
    if (work) { 

    INIT_WORK((struct work_struct *)work, my_wq_function); 

    memcpy(work->msg_to_pc, msg_to_pc, msg_len); 
    work->msg_len = msg_len; 

    ret = queue_work(my_wq, /*(struct work_struct *)RR*/work); 
    printk("kuku ret=%i msg=%s\n",ret,work->msg_to_pc); 

    } 
    return ret; 
} 
//------------------------------------------------------------------------------------------------------------------------------ 
static void netlink_recv_msg(struct sk_buff *skb) 
{ 
    char *msg = "ABCD1234"; 

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

    nlh=(struct nlmsghdr*)skb->data; 
    printk(KERN_INFO "Netlink at kernel received msg payload: %s\n",(char*)NLMSG_DATA(nlh)); 
//rr 
    pid = nlh->nlmsg_pid; 

    send_up_msg_to_workque((uint8_t*) msg, strlen(msg)); 
} 
//------------------------------------------------------------------------------------------------------------------------------------- 

struct netlink_kernel_cfg cfg = { 
    .input = netlink_recv_msg, 
}; 

static int __init rf_driver_start(void) 
{ 
      printk(KERN_INFO "Loading RF Driver module1...\n"); 

    my_wq = create_workqueue("my_queue"); 
      if (!my_wq) 
      { 
         printk("Failed to create work queue\n"); 
      } 

    printk("Entering: %s\n",__FUNCTION__); 
    nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg); 
    if(!nl_sk) 
    { 
      printk(KERN_ALERT "Error creating socket.\n"); 
      return -10; 
    } 


      return 0; 
} 
//-------------------------------------------------------------------------------------------------------------- 
static void __exit rf_driver_end(void) 
{ 
      netlink_kernel_release(nl_sk); 
      flush_workqueue(my_wq); 
      destroy_workqueue(my_wq); 
      printk(KERN_INFO "RF Driver exit...\n"); 
} 

module_init(rf_driver_start); 
module_exit(rf_driver_end); 
+0

Iは、ユーザ空間で機能使用: 私は'len' INTを推測は、このコードは問題である チャーBUF [100]。 ret = recv(sock_fd、buf、100、0); の代わりに ret = recvmsg(sock_fd、&msg_rcv、0); とそれが動作します... 誰もこの奇妙な行動のアイデアを持っていますか? – MotiC

答えて

0

更新、

私はユーザ空間の機能を変更しました〜へ:

char buf[100]; 
ret=recv(sock_fd, buf, 100, 0); 

の代わり:

ret=recvmsg(sock_fd, &msg_rcv, 0); 

とそれが動作する...

誰もがこの奇妙な振る舞いに関するアイデアを持っているのでしょうか?

ありがとうございました。

0

完全なユーザースペースコードを貼り付けてください。

memset(nlh_rcv, 0, NLMSG_SPACE(MAX_PAYLOAD)); 

    iov_rcv.iov_len = nlh_rcv->nlmsg_len; << check to what value is it getting initialized. 
関連する問題