LinuxカーネルでUDPパケットを送信する
-
06-07-2019 - |
質問
プロジェクトの場合、LinuxカーネルスペースからUDPパケットを送信しようとしています。現在、コードをカーネルに「ハードコーディング」していますが(これは最良/最も近い方法ではありません)、簡単なテストを実行しようとしています(" TEST"を送信)。カーネルハッキングの初心者であることに言及する必要があります-私は多くの原則とテクニックに固執しているわけではありません!
コードを実行するたびにシステムがハングし、再起動する必要があります-マウス/キーボードの応答がなく、スクロールとキャップロックのキーライトが一緒に点滅します-これが何を意味するのか分かりませんが、カーネルパニック?
このテストコードではrepeat_sendコードは不要ですが、動作しているときに複数の「送信」を必要とする可能性のある大きなメッセージを送信したい-私が問題の原因になるかどうかわかりませんか?
N.B。このコードはlinux-source / net / core / originのneighbour.cに挿入されているため、NEIGH_PRINTK1を使用しています。これは単なるprintkのマクロラッパーです。
ここで本当に頭をレンガの壁にぶつけているのですが、明らかなものは見当たりません、誰かが正しい方向に私を向けることができますか(または目がくらむほど明らかなエラーを見つけてください!)
これまでの所持品は次のとおりです。
void mymethod()
{
struct socket sock;
struct sockaddr_in addr_in;
int ret_val;
unsigned short port = htons(2048);
unsigned int host = in_aton("192.168.1.254");
unsigned int length = 5;
char *buf = "TEST\0";
struct msghdr msg;
struct iovec iov;
int len = 0, written = 0, left = length;
mm_segment_t oldmm;
NEIGH_PRINTK1("forwarding sk_buff at: %p.\n", skb);
if ((ret_val = sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock)) < 0) {
NEIGH_PRINTK1("Error during creation of socket; terminating. code: %d\n", ret_val);
return;
}
memset(&addr_in, 0, sizeof(struct sockaddr_in));
addr_in.sin_family=AF_INET;
addr_in.sin_port = port;
addr_in.sin_addr.s_addr = host;
if((ret_val = sock.ops->bind(&sock, (struct sockaddr *)&addr_in, sizeof(struct sockaddr_in))) < 0) {
NEIGH_PRINTK1("Error trying to bind socket. code: %d\n", ret_val);
goto close;
}
memset(&msg, 0, sizeof(struct msghdr));
msg.msg_flags = 0;
msg.msg_name = &addr_in;
msg.msg_namelen = sizeof(struct sockaddr_in);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
repeat_send:
msg.msg_iov->iov_len = left;
msg.msg_iov->iov_base = (char *)buf + written;
oldmm = get_fs();
set_fs(KERNEL_DS);
len = sock_sendmsg(&sock, &msg, left);
set_fs(oldmm);
if (len == -ERESTARTSYS)
goto repeat_send;
if (len > 0) {
written += len;
left -= len;
if (left)
goto repeat_send;
}
close:
sock_release(&sock);
}
どんな助けでも大歓迎です、ありがとう!
解決
netpoll API UDPの場合。方法の例については、 netconsole をご覧ください。使用されています。使用しているAPIは、ユーザー空間向けです(ネットワークデータを送信するためにセグメント記述子で遊ぶ必要はありません!)
他のヒント
テキストモードコンソールでコードを実行します(つまり、Ctrl + Alt + F1を押してテキストコンソールに移動します)。このようにして、カーネルパニックはスタックトレースと何が問題なのかに関する追加情報を出力します。
それでも解決しない場合は、スタックトレースで質問を更新してください。
私はあまりLinuxカーネル開発者ではありませんが、printkをそこに入れて、ダウンする前にdmesgを見ることができますか?または、カーネルデバッガーとの接続について考えたことがありますか?
すべての変数をmymethod()関数の外に置いて、静的にする必要があると思います。カーネルスタックのサイズは8KiBに制限されているため、ローカル変数が多すぎる/大きすぎると、スタックオーバーフローとシステムのハングアップが発生する可能性があります。