rpi-sourceでソースコードを取得する時のエラー解消

カーネルモジュール作成に必要なRaspbianのカーネルソースコードをrpi-sourceを利用して取得しようとしたところ、パッケージが足りずエラーが出たため、回避方法を載せておきます。

2024/03/20追記
kernel version 5.10.103-v7+での実行を確認

# 環境
Raspberry pi3 Model B+使用

```terminal
root@raspi:/home/raspi# cat /proc/version
Linux version 4.19.57-v7+ (dom@buildbot) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611)) #1244 SMP Thu Jul 4 18:45:25 BST 2019
```

# 必要なパッケージ＆ソースコードを取得
下記の順番にコマンドを実行することで、Raspbianのカーネルソースコードを取得できます。
ソースコードをコンパイルする際、apt-getコマンドでインストールする5つのパッケージがないとエラーが出るので、最初にこれらを導入します。


```terminal
# apt install git bc bison flex libssl-dev raspberrypi-kernel-headers
# wget https://raw.githubusercontent.com/RPi-Distro/rpi-source/master/rpi-s
ource -O /usr/local/bin/rpi-source && chmod +x /usr/local/bin/rpi-source && /usr
/local/bin/rpi-source -q --tag-update
# rpi-source
# zcat /proc/config.gz > .config.running
# scripts/diffconfig .config.running .config

```

Linux version 4.19.57-v7+ のときの実行内容は下記の通り
```terminal
# apt-get install bc bison flex libssl-dev libncurses5-dev
# wget https://raw.githubusercontent.com/notro/rpi-source/master/rpi-source -O /usr/bin/rpi-source
# chmod +x /usr/bin/rpi-source
# /usr/bin/rpi-source -q --tag-update
# rpi-source
```

# カーネルモジュールのコンパイル
下記のソースコードをコンパイルしました。

```c:kmod.c
/* for kernel module */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>

/* for Netfilter */
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>

/* for modifying IP packets */
#include <linux/skbuff.h>
#include <linux/ip.h>

MODULE_LICENSE("GPL");

static unsigned int
my_hook_func(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
{
        struct iphdr *iph;
        iph = (struct iphdr *)skb_network_header(skb);

        if (iph->protocol == 17)
                printk(KERN_INFO "src : %pI4\n", &iph->saddr);

        return NF_ACCEPT;
}

static const struct nf_hook_ops kmod_nf_ops[] = {
        {
                .hook = my_hook_func,
                .pf = PF_INET,
                .hooknum = NF_INET_PRE_ROUTING,
                .priority = NF_IP_PRI_FIRST,
        },
        {
                .hook = my_hook_func,
                .pf = PF_INET,
                .hooknum = NF_INET_POST_ROUTING,
                .priority = NF_IP_PRI_FIRST,
        },
};

static int __init kmod_init(void)
{
        nf_register_net_hooks(&init_net, kmod_nf_ops, ARRAY_SIZE(kmod_nf_ops));
        printk(KERN_INFO "Init kmod.ko (%s)\n", __func__);
        return 0;
}

static void __exit kmod_exit(void)
{
        nf_unregister_net_hooks(&init_net, kmod_nf_ops, ARRAY_SIZE(kmod_nf_ops));
        printk(KERN_INFO "Exit kmod.ko (%s)\n", __func__);
}

module_init(kmod_init);
module_exit(kmod_exit);
```

```makefile:Makefile
KERNEL_HEADERS=/lib/modules/$(shell uname -r)/build

obj-m := kmod.o

all:
    $(MAKE) -C $(KERNEL_HEADERS) M=$(shell pwd) modules

clean:
    $(MAKE) -C $(KERNEL_HEADERS) M=$(shell pwd) clean
```

なお、Makefileの`all:`または`clean:`の次の行に記載しているコマンドはタブでインデントすること。スペースで記載すると`*** missing separator. Stop.`というエラーが出る。

下記のコマンドでコンパイルや、カーネルモジュールをインストール・アンインストールできます。
なお、カーネルモジュールのインストールに「modprobe」を使うと、依存関係にある他のモジュールをインストールされる可能性があるので、「insmod」を使った方がバグの特定が面倒ではなくなります。

```terminal
$ sudo su
# make
# insmod kmod.ko
# rmmod kmod.ko 
```

追記(2019/8/17):
カーネルモジュールをコンパイルする際は`sudo su`コマンドでrootユーザに切り替えてから行ってください。他のユーザでsudoを付けてmakeしても、正常にコンパイルできない可能性があります。
追記（2019/11/10）：
私の環境で`sudo su`せずにコンパイルを行うと、10時間以上処理を行った挙句エラーを吐き出して止まりました。
カーネル関連のソースコードを1からコンパイルし、何処かでこけたのだと思います。

# 参考
- [http://my-web-site.iobb.net/~yuki/2017-03/raspberry-pi/kernel-modules/](http://my-web-site.iobb.net/~yuki/2017-03/raspberry-pi/kernel-modules/)
- [Raspberrypi3でデバイスドライバを作る](https://qiita.com/cello_piano_violin/items/b93f5eae97a96a394d7e)
- [Linux技術トレーニング　基本管理コース II](https://users.miraclelinux.com/technet/document/linux/training/2_1_1.html)
- [RPi-Distro/rpi-source](https://github.com/RPi-Distro/rpi-source)