ネットでNuttXのIPv6関係のことを検索しても、情報はおおくはないのですが、調べてみたところ stm32f4discoveryにipv6のコンフィグが入っていることがわかりました。そこでさらにしらべたのですが、Ethernetでは動作するようですが、残念ながらそれ以上のことはわかりませんでした。
そこでソースをみたところ、CDCECMはIPv6に対応している様子で、いったんBlack PillでCDCECMをコンパイルし書き込んでみたのですが、IPv6は無論のこと、IPv4も動作しませんでした。どうやら、RNDISはF4のOTGFS依存であり、CDCECMはF103系のUSBDEV依存のようです。
そこで今一度気を取り直し、RNDISにIPv6関連の設定を入れ、動作しない場合は、ソースに手を入れるという方向でやろうとしたところ、結局コンフィグだけでアドレス取得、PING6, telnet over ipv6ができたので、備忘録として本稿を挙げてみることにしました。また、今回はコンフィグだけでなく、Black Pillを接続する母艦側の設定も挙げてあります。
まずは、weact-f401cc(F401cc Black Pill)向けのIPv6のコンフィグ設定です。
$ cat boards/arm/stm32/weact-f401cc/configs/rndis_ipv6/defconfig # # This file is autogenerated: PLEASE DO NOT EDIT IT. # # You can use "make menuconfig" to make any modifications to the installed .config file. # You can then do "make savedefconfig" to generate a new defconfig file that includes your # modifications. # # CONFIG_ARCH_FPU is not set # CONFIG_NSH_ARGCAT is not set # CONFIG_NSH_CMDOPT_HEXDUMP is not set # CONFIG_NSH_CMDPARMS is not set CONFIG_ARCH="arm" CONFIG_ARCH_BOARD="weact-f401cc" CONFIG_ARCH_BOARD_WEACT_F401CC=y CONFIG_ARCH_BUTTONS=y CONFIG_ARCH_CHIP="stm32" CONFIG_ARCH_CHIP_STM32=y CONFIG_ARCH_CHIP_STM32F401CC=y CONFIG_ARCH_STACKDUMP=y CONFIG_BOARD_LATE_INITIALIZE=y CONFIG_BOARD_LOOPSPERMSEC=8499 CONFIG_BUILTIN=y CONFIG_FS_PROCFS=y CONFIG_HAVE_CXX=y CONFIG_HAVE_CXXINITIALIZE=y CONFIG_HOST_WINDOWS=y CONFIG_INTELHEX_BINARY=y CONFIG_MAX_TASKS=16 CONFIG_MAX_WDOGPARMS=2 CONFIG_NFILE_DESCRIPTORS=8 CONFIG_NFILE_STREAMS=8 CONFIG_NSH_BUILTIN_APPS=y CONFIG_NSH_FILEIOSIZE=512 CONFIG_NSH_LINELEN=64 CONFIG_NSH_READLINE=y CONFIG_PREALLOC_MQ_MSGS=4 CONFIG_PREALLOC_TIMERS=4 CONFIG_PREALLOC_WDOGS=16 CONFIG_RAM_SIZE=65536 CONFIG_RAM_START=0x20000000 CONFIG_RAW_BINARY=y CONFIG_RR_INTERVAL=200 CONFIG_SCHED_WAITPID=y CONFIG_SDCLONE_DISABLE=y CONFIG_START_DAY=6 CONFIG_START_MONTH=12 CONFIG_START_YEAR=2011 CONFIG_STM32_JTAG_SW_ENABLE=y CONFIG_STM32_PWR=y CONFIG_STM32_SPI1=y CONFIG_STM32_USART2=y CONFIG_SYSTEM_NSH=y CONFIG_SYSTEM_NSH_CXXINITIALIZE=y CONFIG_SYSTEM_PING=y CONFIG_SYSTEM_PING6=y CONFIG_USART2_RXBUFSIZE=128 CONFIG_USART2_SERIAL_CONSOLE=y CONFIG_USART2_TXBUFSIZE=128 CONFIG_USER_ENTRYPOINT="nsh_main" CONFIG_BOARDCTL_USBDEVCTRL=y CONFIG_NET=y CONFIG_NET_ICMPv6=y CONFIG_NET_ICMPv6_AUTOCONF=y CONFIG_NET_ICMPv6_NEIGHBOR=y CONFIG_NET_ICMPv6_SOCKET=y CONFIG_NET_IPv6=y CONFIG_NET_TCP=y CONFIG_NET_TCP_WRITE_BUFFERS=y CONFIG_NET_UDP=y CONFIG_NET_BROADCAST=y CONFIG_NET_ICMP=y CONFIG_NET_ICMP_SOCKET=y CONFIG_NET_ARP_SEND=y CONFIG_NET_STATISTICS=y CONFIG_NET_LOOPBACK=y CONFIG_NET_SOCKOPTS=y CONFIG_NETDB_DNSCLIENT=y CONFIG_NETDB_DNSSERVER_IPv4ADDR=0x0 CONFIG_NETDEV_PHY_IOCTL=y CONFIG_NETDEV_IFINDEX=y CONFIG_NETDEVICES=y CONFIG_NETINIT_DHCPC=y CONFIG_NETINIT_NOMAC=y CONFIG_NETINIT_SWMAC=y CONFIG_NETINIT_MACADDR_1=0xbabecafe CONFIG_NETINIT_MACADDR_2=0x00e0 CONFIG_NETINIT_THREAD=y CONFIG_NETINIT_IPADDR=0x0a000002 CONFIG_NETINIT_DRIPADDR=0x0a000001 CONFIG_NETINIT_NETMASK=0xffffff00 CONFIG_NETUTILS_DHCPC=y CONFIG_NETUTILS_TELNETD=y CONFIG_RNDIS=y CONFIG_SCHED_HPWORK=y CONFIG_STM32_OTGFS=y CONFIG_USBDEV=yコンフィグはここまでです。次に、"母艦上で認識される疑似MACアドレス" でRNDISを初期化するように、ソースをstm32_bringup.cへ追加します。
#boards/arm/stm32/weact-f401cc/src/stm32_bringup.c #前略 #ifdef CONFIG_RNDIS # include <nuttx/usb/rndis.h> #endif #中略 int stm32_bringup(void) { int ret = OK; #中略 #if defined(CONFIG_RNDIS) uint8_t mac[6]; /* get pseudo mac address from the 3rd 32bits of cpuid */ unsigned long *pmac = (unsigned long *)0x1FFF7A18; mac[0] = 0xa0; /* TODO */ mac[1] = (CONFIG_NETINIT_MACADDR_2 >> (8 * 0)) & 0xff; mac[2] = (pmac[0] >> (8 * 3)) & 0xff; mac[3] = (pmac[0] >> (8 * 2)) & 0xff; mac[4] = (pmac[0] >> (8 * 1)) & 0xff; mac[5] = (pmac[0] >> (8 * 0)) & 0xff; usbdev_rndis_initialize(mac); #endif #後略なお、CONFIG_NETINIT_MACADDR_2はデフォルトで0x00e0ですが、母艦で認識されるMAC アドレスと、ターゲット上のMAC アドレスは異なる必要があるので、上述の様に先頭のMACアドレスはハードコーディングされていますが、たとえば0x0aだとマックアドレスが固定されませんでした...元々のソースにToDoとあるのはそのためでもあるかもしれません。 またmac addressは疑似的にuniqueになるようにしているので、デバイスごとにmacアドレスを変えてビルドする必要はありません。 今回、RNDISで関係のある "ターゲット上で認識される疑似マックアドレス" のコードは以下の部分です。
$ diff -urN ../apps/netutils/netinit/netinit.c.orig ../apps/netutils/netinit/netinit.c --- ../apps/netutils/netinit/netinit.c.orig 2020-09-21 00:09:46.000000000 +0900 +++ ../apps/netutils/netinit/netinit.c 2021-03-06 22:33:47.000000000 +0900 @@ -299,11 +299,24 @@ mac[0] = (CONFIG_NETINIT_MACADDR_2 >> (8 * 1)) & 0xff; mac[1] = (CONFIG_NETINIT_MACADDR_2 >> (8 * 0)) & 0xff; - +#if defined(CONFIG_STM32_STM32F10XX) + unsigned long *pmac = (unsigned long *)0x1FFFF7F0; + mac[2] = (pmac[0] >> (8 * 3)) & 0xff; + mac[3] = (pmac[0] >> (8 * 2)) & 0xff; + mac[4] = (pmac[0] >> (8 * 1)) & 0xff; + mac[5] = (pmac[0] >> (8 * 0)) & 0xff; +#elif defined(CONFIG_STM32_STM32F4XXX) + unsigned long *pmac = (unsigned long *)0x1FFF7A18; + mac[2] = (pmac[0] >> (8 * 3)) & 0xff; + mac[3] = (pmac[0] >> (8 * 2)) & 0xff; + mac[4] = (pmac[0] >> (8 * 1)) & 0xff; + mac[5] = (pmac[0] >> (8 * 0)) & 0xff; +#else mac[2] = (CONFIG_NETINIT_MACADDR_1 >> (8 * 3)) & 0xff; mac[3] = (CONFIG_NETINIT_MACADDR_1 >> (8 * 2)) & 0xff; mac[4] = (CONFIG_NETINIT_MACADDR_1 >> (8 * 1)) & 0xff; mac[5] = (CONFIG_NETINIT_MACADDR_1 >> (8 * 0)) & 0xff; +#endif /* Set the MAC address */コンフィグ・コード追加修正がすんだらビルド・書き込みを済ましておきます。 続いて母艦側の設定です。 まず、接続の概要です。IPv4/IPv6の固定回線とルータがあること、母艦はLinux/Debianであることが前提です。図にすると以下のようになります。 簡単に説明しますと、eth0-eth2とありますがBlack Pill を USB/RNDISで接続し、Debian上でethXとして認識させ、差し込まれたときに母艦の外側インターフェースであるenp2s0を含んだbr0に追加する、ということになります。こうすることで、Black Pill上のインターフェースeth0はインターネットルータから直接 IPv4アドレスとIPv6アドレスを取得でき、母艦側でDHCPDやRADVDなどを別途用意設定する必要がなくなります。具体的には以下のようになります。 まず、母艦上で ブリッジが使えるようにしておきます。
apt-get install bridge-utilsつづいて母艦上のブリッジの設定をおこないますが、br0にenp2s0を追加するので、enp2s0の設定は削除しておいてください。
#/etc/network/interfaces/br0 auto br0 iface br0 inet static address 192.168.1.2 netmask 255.255.255.0 gateway 192.168.1.1 bridge_ports enp2s0 iface br0 inet6 auto次にudevにてそれぞれのBlack Pill毎に母艦上でethXとして認識させるようにします。なお、マックアドレスは接続時に "ip a" で確認できます。
#/etc/udev/rules.d/70-persistent-net.rules SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="a0:e0:31:35:AA:BB", NAME="eth0" SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="a0:e0:33:30:CC:DD", NAME="eth1" SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="a0:e0:38:36:EE:FF", NAME="eth2"udev ruleを反映するには、udevadm triggerとするか再起動してください。 さらにRNDIS接続するBlack Pill用に接続時にbr0に追加するようにします。
#/etc/network/interfaces/eth0 allow-hotplug eth0 iface eth0 inet manual pre-up brctl addif br0 eth0 pre-down brctl delif br0 eth0
#/etc/network/interfaces/eth1 allow-hotplug eth1 iface eth1 inet manual pre-up brctl addif br0 eth1 pre-down brctl delif br0 eth1
#/etc/network/interfaces/eth2 allow-hotplug eth2 iface eth2 inet manual pre-up brctl addif br0 eth2 pre-down brctl delif br0 eth2設定は以上です。続いて動作の確認をおこないます。ターゲットはUSART2でシリアルコンソールがつかえるので、ターミナルソフトで115200/8n1で接続してください。 まずは母艦に接続されていない状態のifconfigは以下のようになります。
NuttShell (NSH) NuttX-9.1.0 nsh> ifconfig lo Link encap:Local Loopback at UP inet addr:127.0.0.1 DRaddr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 inet6 DRaddr: ::1/128 eth0 Link encap:Ethernet HWaddr 00:e0:33:30:CC:DD at UP inet addr:0.0.0.0 DRaddr:10.0.0.1 Mask:255.255.255.0 inet6 addr: ::/0 inet6 DRaddr: ::/0 IPv4 IPv6 TCP UDP ICMP ICMPv6 Received 0000 0000 0000 0000 0000 0000 Dropped 0000 0000 0000 0000 0000 0000 IPv4 VHL: 0000 Frg: 0000 IPv6 VHL: 0000 Checksum 0000 ---- 0000 0000 ---- ---- TCP ACK: 0000 SYN: 0000 RST: 0000 0000 Type 0000 0000 ---- ---- 0000 0000 Sent 0000 0000 0000 0000 0000 0000 Rexmit ---- ---- 0000 ---- ---- ---- nsh>続いて母艦に接続し、母艦側でip aにてRNDIS接続を確認します。
9: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1306 qdisc pfifo_fast master br0 state UNKNOWN group default qlen 1000 link/ether a0:e0:33:30:CC:DD brd ff:ff:ff:ff:ff:ff inet6 fe80::a2e0:33ff:fe30:CCDD/64 scope link valid_lft forever preferred_lft forever例ではeth1に接続されていること、"母艦上で認識されるMACアドレス"と"ターゲット上で認識されるMACアドレス"がことなることが確認できました。 つづいてBlack Pill上で今一度ネットワーク接続を確認します。
nsh> ifconfig lo Link encap:Local Loopback at UP inet addr:127.0.0.1 DRaddr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 inet6 DRaddr: ::1/128 eth0 Link encap:Ethernet HWaddr 00:e0:33:30:CC:DD at UP inet addr:192.168.1.210 DRaddr:192.168.1.1 Mask:255.255.255.0 inet6 addr: 240d:XXXX:YYYY:ZZZZ:AAAA:BBBB:CCCC:DDDD/64 inet6 DRaddr: fe80::1/64 IPv4 IPv6 TCP UDP ICMP ICMPv6 Received 0024 000f 0000 0004 0000 000f Dropped 0020 0000 0000 0000 0000 000e IPv4 VHL: 0000 Frg: 0000 IPv6 VHL: 0000 Checksum 0000 ---- 0000 0000 ---- ---- TCP ACK: 0000 SYN: 0000 RST: 0000 0000 Type 0000 0000 ---- ---- 0000 0009 Sent 0002 0006 0000 0002 0000 0006 Rexmit ---- ---- 0000 ---- ---- ---- nsh>参考までにルータのIPv4 DHCP リースに、"ターゲット上で認識されるMACアドレス"にて、以下の様に正常に認識されていました。
# IPv4 00:e0:33:30:CC:DD 192.168.1.210 50282 nuttx LAN3IPv6/IPv4のアドレス取得には若干時間がかかる場合がありますが、基本的には上述の設定で、IPv6/IPv4接続が同時にできます。ちなみに今回の設定にはtelnetdが入っているので外部から接続すると以下のようになります。
$ telnet 240d:XXXX:YYYY:ZZZZ:AAAA:BBBB:CCCC:DDDD Trying 240d:XXXX:YYYY:ZZZZ:AAAA:BBBB:CCCC:DDDD... Connected to 240d:XXXX:YYYY:ZZZZ:AAAA:BBBB:CCCC:DDDD. Escape character is '^]'. NuttShell (NSH) NuttX-9.1.0 nsh> uname -a NuttX 9.1.0 e4e4cce696-dirty Mar 18 2021 17:53:02 arm weact-f401cc nsh> free total used free largest Umem: 47744 29824 17920 17856 nsh> ps PID PRI POLICY TYPE NPX STATE EVENT SIGMASK STACK COMMAND 0 0 FIFO Kthread N-- Ready 00000000 000000 Idle Task 1 224 FIFO Kthread --- Waiting Signal 00000000 002052 hpwork 3 100 FIFO Task --- Waiting Semaphore 00000000 002052 init 4 100 FIFO Task --- Waiting Semaphore 00000000 002028 Telnet daemon 0x20005fb0 5 100 FIFO Task --- Waiting Semaphore 00000000 002028 Telnet daemon 0x20006490 7 100 FIFO Kthread --- Waiting Semaphore 00000000 001020 telnet_io 8 100 FIFO Task --- Running 00000000 002044 Telnet session nsh>401CCでもIPv6が動作しメモリーもそこそこ残っているのですが、RAM/Flashともに倍ある411CEを使う方が無難だなと思いました。なお今回使ったインターネット回線はNuro光 G2V ですが、フレッツ光でもIPoEでIPv6の接続ができているなら、(いずれにしてもIPv6ファイアウォール設定は必要ですが...)上述の母艦設定で行けると思います。Ethernetを使わずUSBだけでIPv6/IPv4が使えるのはGoodですね。 今回は以上です。それでは。
コメント
コメントを投稿