OCN IPv6 を NetBSD で使う

OCN IPv6 なるサービスが 2005 年 12 月から始まっていたことに、 今更 (2006-01-12) ながら気づいたので、とりあえず申し込む。 Windows XP SP2 しかサポートしませんと書かれていて、 専用の接続プログラムが必要だけど、 1701 ポートを開けろと書かれていて L2TP っぽかったので、 NetBSD 3.0 で使えるか試してみた。 結局 L2TP + PPP して、DHCPv6 で prefix delegation 受けるだけで使えたけれど、 いくつかはまったのでメモ。

rp-l2tp

pkgsrc の net/rp-l2tp は起動しない (PR pkg/32275)。

rp-l2tp-0.4.tar.gz を取ってきて pkgsrc を参考に手でコンパイルすると、 起動するものの、 l2tpd と pppd の間の通信がうまくいかない。 どうも pppd が HDLC フレームを期待しているのに、 pty を HDLC ラインディシプリンにしていないことが原因ぽい。 HDLCDISCTIOCSETD してみようとしたけど、 ENXIO になってしまった。

結局、http://software.nautilus6.org/packages/rp-l2tp/ から async-pppd.so を使うとうまくいった。 Nautilus6 のやつは hostname のバグも直っているし、ありがとー。

List 1: l2tp.conf
# Global section (by default, we start in global mode)
global

# Load handlers
load-handler "async-pppd.so"
load-handler "cmd.so"

# Bind address
listen-port 1701

# Configure the sync-pppd handler.  You MUST have a "section sync-pppd" line
# even if you don't set any options.
section async-pppd

lac-pppd-opts "user your-OCN-user-name noipdefault lcp-echo-interval 30 lcp-echo-failure 6 +ipv6 mtu 1390"

# Peer section
section peer
peer your-OCN-IPv6-server
port 1701
lac-handler async-pppd
hide-avps no

# Configure the cmd handler.  You MUST have a "section cmd" line
# even if you don't set any options.
section cmd

ところで、 pppd には ipv6defaultroute みたいなオプションはないのかな。 とりあえず、ipv6-up スクリプトでデフォルト経路を設定した。

dhcp6c

KAME から dhcp6 を取ってきてコンパイルするだけ。 だと思っていたのに動かない。 Reply が ppp0 までは来ているのに、 dhcp6c に届かない。 どうも insock じゃなくて outsock に上がってきている気がする。 UDP ソケットに対する shutdown(2) のセマンティクスを知らないので、 誰が悪いのかは分からないけれど。 とりあえず outsock から読むという荒技で逃げると動いた。 後で調べて報告しなきゃ。

List 2: dhcp6c.conf
interface ppp0 {
	send ia-pd 0;
};

id-assoc pd {
	prefix-interface vr0 {
		sla-len 0;
	};
};

OCN IPv6 ユーザ網インタフェース仕様書 第 1.0 版

後から (次の rp-l2tp の問題をぐぐってて) 見つけたんだけど、 http://www.v6.ntt.net/07_document.html に、 仕様書が置いてあった。

rp-l2tp 再度

動いたと思っていたら、inbound は問題ないのに、 大きい outbound パケットが通らないことに気づいた。 だいたい 800〜900 バイトより大きいと通らない。 どうも、pppd から l2tp へ渡すフレームが 1 KB ごとに上がってきて、 async-pppd.so がそれに対応していないのが原因らしい。

ダーティーハックとして、 EWOULDBLOCK が返るまで読めるだけ read(2) すると動くかなと思ったけど、駄目だった。 スピンして待つのはさすがに嫌なので、 面倒だけどいったんイベント待ちに戻ることにして、 struct slave にバッファを用意。