前回までは、 setsocopt
関数はOSのシステムコールを呼んでいるらしいというところまで確認した。
今回は、カーネルのシステムコールの実装を覗いてみたいと思います。(確認した時のカーネルのバージョンは linux-4.19.172
kernel/git/stable/linux.git - Linux kernel stable tree )
setsocopt
で検索すると、以下のファイルにそれっぽい定義がありました。
linux-4.19.172/net/packet/af_packet.c
すると以下の箇所に今回焦点を当てているオプションの PACKET_ADD_MEMBERSHIP
に関する処理の定義があります。
以下の copy_from_user
はメモリ空間からカーネル空間に変数のメモリをコピーする関数です。
ここで (copy_from_user(&mreq, optval, len))
では文字列のポインタ optval を packet_mreq_max 構造体にコピーしています。
つまり、ここでデータを指定の構造体に入れ直していると考えて良さそうです。
したがって、 copy_from_user において文字列データとしてユーザー空間からデータを取得するため、ユーザー空間のプログラムでは構造体でも文字列データでも同じように処理が出来たと考えられます。
これで一旦最初の疑問は解消できたように思います!
static int packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct packet_sock *po = pkt_sk(sk); int ret; if (level != SOL_PACKET) return -ENOPROTOOPT; switch (optname) { case PACKET_ADD_MEMBERSHIP: case PACKET_DROP_MEMBERSHIP: { struct packet_mreq_max mreq; int len = optlen; memset(&mreq, 0, sizeof(mreq)); if (len < sizeof(struct packet_mreq)) return -EINVAL; if (len > sizeof(mreq)) len = sizeof(mreq); if (copy_from_user(&mreq, optval, len)) return -EFAULT;