3

状況: 私のコードは、基本的に Linux カーネルのドライバーにハッキングされています。重要な生イベントがメイン システムに送信される前に、ユーザー空間のアプリケーションに通知したいと考えています。

解決の手順: カーネル空間から UDP パケットを送信する良い例を見つけました: http://kernelnewbies.org/Simple_UDP_Server。彼らは INADDR_LOOPBACK をターゲットアドレスとして使用します。これはまさに私が望むものです。

これは割り込みコンテキストであるため、ワーク キューを使用してパケットを送信することにしました (BUG: Scheduling while atomic without it が発生しました)。したがって、私の送信コードは、メイン プロセスの INIT_WORK と schedule_work で起動されるワーク キュー構造体にラップされた kernelnewbies コードに基づいています。私は自分の作業キューを宣言していません。

この質問は、ローカルホストとの間でデータを送受信できないことを示唆しているため、Netpoll API は使用していません。「自分宛には送信できません」

問題: カーネルから送信され、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 が静的であり、ワーク キューから container_of を使用して buf と len を取得する必要があることです。私は完全に静的なコンテキストで作業しています。私の 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
�&lt;����,<,�,�,�,,,,
                    ,=
-------------------------------------------------------
-------------------------------------------------------
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 バイトしか送信しないため、パケットの断片化も発生しないはずです。パケットロスもありません。パケットを送信するたびに、受信もされます。

更新: IT WORKS ..しかし、なぜ最初に、alk からのコメントのおかげで、明らかなことを忘れてしまったのかわかりません。データが送信される直前にログを記録します。schedule_work を呼び出す前にログを記録しました。これで、iov から void * ポインターに格納される前に、send メソッド workmsg->buf に直接ログインするようになりました。データはすでに破損しています。

構造体 ksocket_workmessage には char * があり、私のデータは char [] で、構造体のポインターに割り当てられました。

私が今行ったことは、構造体 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';

私の最初のアプローチが失敗した場所を誰かが教えてくれれば、それを正しい答えとして喜んで受け入れます。

4

1 に答える 1