簡體   English   中英

將小型UDP數據包從Linux內核發送到LOOPBACK

[英]Sending small UDP packets from the Linux Kernel to LOOPBACK

情況:我的代碼基本上被黑客入侵了Linux內核的驅動程序。 我想在用戶空間中通知一個關於值得注意的原始事件的應用程序,然后才能將它們發送到主系統。

解決方案的步驟:我在這里找到了一個從內核空間發送UDP數據包的好例子: http//kernelnewbies.org/Simple_UDP_Server 他們使用INADDR_LOOPBACK作為目標地址,這正是我想要的。

由於這是中斷上下文,我決定使用工作隊列來發送數據包(我得到了BUG:在沒有它的情況下進行原子調度)。 因此,我的發送代碼基於kernelnewbies代碼,該代碼包含在主進程中使用INIT_WORK和schedule_work觸發的工作隊列結構中。 我沒有宣布自己的工作隊列。

我沒有使用Netpoll API,因為此問題表明無法從localhost發送數據。 “你不能發給自己”

問題:從內核發送並從我的UDP接收器接收的數據很少匹配。 我不知道為什么會這樣。

用於測試的虛擬數據的代碼,包括工作隊列的結構的定義:

static struct socket *sock_send;
static struct sockaddr_in addr_send;

static struct ksocket_workmessage {
    unsigned char *buf;
    int len;
    struct work_struct workmessage;
} workmsg;


unsigned char testmsg[] = {'T', 'e', 's', 't', 'i', 'n', 'g', 'm', 's', 'g', '\0'};
workmsg.buf = testmsg;
workmsg.len = 11;
INIT_WORK(&workmsg.workmessage, handle_workmessage);
schedule_work(&workmsg.workmessage);

發送實際數據包就像kernelnewbies示例中的“int ksocket_send”。 唯一的區別是我的send_socket是靜態的,我必須從工作隊列中獲取buf和len與container_of。 我在一個完全靜態的環境中工作。 我的handle_workmessage方法也是靜態的:

static void handle_workmessage(struct work_struct *work)
{
        struct msghdr msg;
        struct iovec iov;
        mm_segment_t oldfs;
        int size = 0;

        struct ksocket_workmessage *workmsg = container_of(work, struct ksocket_workmessage, workmessage);


        if (sock_send->sk==NULL)
             return;

        iov.iov_base = workmsg->buf;
        iov.iov_len = workmsg->len;

        msg.msg_flags = 0;
        msg.msg_name = &addr_send;
        msg.msg_namelen  = sizeof(struct sockaddr_in);
        msg.msg_control = NULL;
        msg.msg_controllen = 0;
        msg.msg_iov = &iov;
        msg.msg_iovlen = 1;
        msg.msg_control = NULL;

        oldfs = get_fs();
        set_fs(KERNEL_DS);
        size = sock_sendmsg(sock_send,&msg,workmsg->len);
        set_fs(oldfs);
}

接收端如下所示:

int main(int argc, char**argv)
{
int sockfd,n;
struct sockaddr_in servaddr;
socklen_t len;
unsigned char mesg[1000];

sockfd=socket(AF_INET,SOCK_DGRAM,0);

bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(REC_PORT);
bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));

for (;;)
{
  n = recv(sockfd,mesg,1000,0);
  printf("-------------------------------------------------------\n");
  mesg[n] = 0;
  printf("Received the following: %d bytes\n", n);
  printf("%s",mesg);
  printf("%c",mesg[0]);
  printf(",%c",mesg[1]);
  printf(",%c",mesg[2]);
  printf(",%c",mesg[3]);
  printf(",%c",mesg[4]);
  printf(",%c",mesg[5]);
  printf(",%c",mesg[6]);
  printf(",%c",mesg[7]);
  printf(",%c",mesg[8]);
  printf(",%c\n",mesg[9]);
  //printf("%c\n",mesg[0]);
  printf("-------------------------------------------------------\n");
  memset(mesg, 0, sizeof(mesg));
 }
}

輸出看起來已損壞,即使我總是發送完全相同的消息用於測試目的:

-------------------------------------------------------
Received the following: 11 bytes
�}|�ingmsg�,},|,�,i,n,g,m,s,g
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
����d����,�,�,�,d,�,�,�,,
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
�}|�ingmsg�,},|,�,i,n,g,m,s,g
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
,�,�,�,�,2,k,�,�,�
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
�<����,<,�,�,�,,,,
                    ,=
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
�}|�ingmsg�,},|,�,i,n,g,m,s,g
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
�}|�ingmsg�,},|,�,i,n,g,m,s,g
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes


,,%,�,,,,,,
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
TestingmsgT,e,s,t,i,n,g,m,s,g
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
�}|�ingmsg�,},|,�,i,n,g,m,s,g
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
 ����Vk��1k ,�,�,�,�,V,k,�,�,1
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
TestingmsgT,e,s,t,i,n,g,m,s,g
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
,,,,,�,,�,,
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
,,
  ,�,,,,,�,<
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
�}|�ingmsg�,},|,�,i,n,g,m,s,g
-------------------------------------------------------

這可能是什么原因? 由於它有時與預期輸出“TestingmsgT,e,s,t,i,n,g,m,s,g”有效,因此它不應該是技術限制。 也不會發生數據包碎片,因為我只發送11個字節。 也沒有丟包。 每次我發送數據包時,它也會被收到。

更新:它工作..但我不知道為什么首先,感謝來自alk的評論,我忘了顯而易見的。 在發送數據之前記錄。 我在調用schedule_work之前做了日志。 現在我直接在我的send方法workmsg-> buf中登錄,甚至在存儲到iov的void *指針之前。 那里的數據已經被破壞了。

struct ksocket_workmessage有一個char *,我的數據是char []並被分配給struct的指針。

我現在做的是更改我的struct ksocket_workmessage中的數據類型:

struct ksocket_workmessage {
        unsigned char buf[11];
        int len;
        struct work_struct workmessage;
} workmsg;

由於我沒有指針,我無法創建我的unsigned char testmsg [],所以我直接分配了buf:

workmsg.buf[0] = 'T';
workmsg.buf[1] = 'e';
workmsg.buf[2] = 's';
workmsg.buf[3] = 't';
workmsg.buf[4] = 'i';
workmsg.buf[5] = 'n';
workmsg.buf[6] = 'g';
workmsg.buf[7] = 'm';
workmsg.buf[8] = 's';
workmsg.buf[9] = 'g';
workmsg.buf[10] = '\0';

如果有人能告訴我我最初的方法失敗了,我很樂意接受它作為正確的答案。

因為它有時會起作用,有時候我不會建議問題是你正在尋找已經免費的內存()d。 因此,內容有時是正確的,有時它們會被破壞。 由於本地緩沖區很好,因此必須在內核中將其復制到本地內存之前。

確實是unsigned char testmsg[]聲明為局部變量?

由於消息不會立即發送,因此您傳遞的testmsg地址位於堆棧中。 如果存在后續的功能調用,則它們將在發送之前重寫消息的內容。 然后,您有時會看到正確的信息,有時則看不到。 取決於工作的安排。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM