スキップしてメイン コンテンツに移動

Nuttx: IPv6 over RNDIS on F411/F401 Black Pill

ネットで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 LAN3
IPv6/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ですね。
今回は以上です。それでは。

コメント

このブログの人気の投稿

Hyper-V Server2019にワークグループ環境下でWindows10(1809)から接続

Hyper-V server 2019に、ワークグループ環境にてWindows10(1809)から接続してみました。Windows10にHyper-V管理ツールがインストールされていることと、Hyper-V Serverをインストール済であることが前提です。以下、Hyper-V serverは名前がHyperVSV、アドレスは192.168.1.110としています。 まず、Hyper-V server上で、powershellを起動し、以下のコマンドを入力します。 Enable-WSManCredSSP -Role Server -Force 続いて、クライアントのWindows10のpowershell で以下のコマンドを入力します。 winrm quickconfig -Force Enable-WSManCredSSP -Role Client -DelegateComputer * -Force さらに、クライアントマシンで、gpedit(グループポリシーエディタ)を起動し、以下の要領でポリシーを設定します。 a. [コンピューターの構成]->[管理テンプレート]->[システム]->[資格情報の委任]->[NTLMのみのサーバー認証で新しい資格情報の委任を許可する] を有効にし、サーバを一覧に追加[表示...]ボタンをクリックして、「WSMAN/*」を追加 b. [コンピューターの構成]->[管理テンプレート]->[システム]->[資格情報の委任]->[NTLM のみのサーバー認証で保存された資格情報の委任を許可する] を有効にし、サーバを一覧に追加[表示...]ボタンをクリックして、「*」を追加 また、名前解決できるように、(notepadを管理者権限で実行し)C:\Windows\System32\Drivers\etc\hostsにサーバ名とIPアドレスの対を追加。 192.168.1.110 HyperVSV 最後に、Hyper-Vマネージャーを起動し、Windows10からHyper-V サーバに接続します。手順は以下の通りです。 「サーバーに接続」->コンピュータの選択->別のコンピューターに[HyperVSV]と入力し、[別のユーザーとして接続する

wsdd を使ってSamba サーバをネットワークに表示

Windows 10のアップデートで、セキュリティー対応のため、smbv1がデフォルトではインストールされなくなり、Samba serverがエクスプローラーのネットワークに表示されなくなってしまいました。そこで、いくつか方法を調べたのですが、linuxでwsdの実装がないか探したところ、 https://github.com/christgau/wsdd が、見つかりましたので、さっそくインストールしてみました。まだパッケージにはないようですが、インストール自身は簡単です。wsdd自体は以下のように取得し、linkを張っておきます。 cd /usr/local/bin/ sudo wget https://raw.githubusercontent.com/christgau/wsdd/master/src/wsdd.py sudo chmod 755 wsdd.py sudo ln -sf wsdd.py wsdd こちらのsambaサーバはDebianなので、/etc/systemd/system/wsdd.serviceは以下のようにしました。 [Unit] Description=Web Services Dynamic Discovery host daemon Requires=network-online.target After=network.target network-online.target multi-user.target [Service] Type=simple ExecStart=/usr/local/bin/wsdd -d MYDOMAIN [Install] WantedBy=multi-user.target wsdd -d MYDOMAINのところを、環境にあわせて書き換えてください。 次に、systemdに登録・起動テストを行います。 systemctl enable wsdd systemctl start wsdd 起動に成功すると、エクスプローラーのネットワークに表示されます。  なおこのwsddはpython3が必要です。一度試してみてください。SMBv1/CIFSを停止していても、大丈夫です。 cで書かれたほかのwsddの実装もあるようなので、いずれパッケージになるかもしれませ

フレッツ光クロス:MAP-E ROUTER by Debian Box (iptables)

フレッツ光クロスがようやく開通したので、Debianにてrouterを構成し接続してみました。なお、プロバイダーを選ぶにあたっては、IPoE方式がそれぞれ異なるため検討したところ、IPoEでは、MAP-Eでもv6plusとocnバーチャルコネクトがあり、前者がポート数240なのに対し、後者は約4倍のポート数が使えるようなネットの情報をみて、OCNバーチャルコネクトを選択しました。(プロバイダーとしてはぷららです。なおDS-LiteはCE側でのNATではないので今回は見送りました。)そこで、OCN バーチャルコネクトをDebian(iptables)で実現するとどうなるかと思い、ネットの情報を頼りにしつつ、設定した次第です。 実際に試した結果、とりあえず通信できていますが、MAP-Eは本来マッピングルールをマップサーバから取得するはずなので、今回のやり方が正解とはいえませんし、仕様変更されると通信できなくなる可能性があります。あくまでも参考程度ですが、本稿をUPしてみました。 2023/03/16追記: こちら にゲームコンソールNAT越え(Nintendo Switch ナットタイプ A判定)対応版を投稿しました。 2023/03/28追記:※1の記述および3行無効化によりNAT越え(Nintendo Switch ナットタイプ B判定)できるようになりました。 構成は以下の通りです。 ルーターがDebianで回線がOCNバーチャルコネクトであること以外はなにも特別なところはない構成です。 さて、いきなり設定ですが、まず、割り当てられたプレフィックスを確認します。 確認は、 dhclient -6 -d -P enp2s0 とします。出力の中に 前略 RCV: | | X-- IAPREFIX 2400:4050:5c71:af00::/56 後略 このようにプレフィックスが表示されるので、その確認したプレフィックスを書き留めておきます。これを こちらで 入力します。すると、 CE: 2400:4050:5c71:af00:99:f171:c600:2f00 IPv4 アドレス: 153.241.113.198 ポート番号:(1776-1791 2800-2815 3824-3839) 4848-4863 5872-5887 6896-