仙石浩明の日記

2009 : January

2009年1月19日

SOTEC C101 (OLEVIA X10A-1160) で Linux (Ubuntu) を使う場合の注意点

香港の旺角電脳中心で買った OLEVIA X10A-1160 は、 Ubuntu 8.04 LTS がプレインストールされていた。 そのまま使うぶんには問題無いが、 Ubuntu のアップデートをインストールしてしまうと (正確に言えばカーネルを更新すると)、 OLEVIA X10A-1160 固有の設定が無効になり、 無線LAN やタッチパッドが使えなくなるなどの問題が生じる。 Ubuntu アップデートを行なった後、 あるいは新規に GNU/Linux (Ubuntu に限らず) をインストールする場合に、 OLEVIA X10A-1160 固有の設定を行なうためのメモ。

OLEVIA X10A-1160 は、 SOTEC C101 と (キーボード配列や天板のデザインを除けば) 同等であるため、 以下の対策は SOTEC C101 に Ubuntu 等の GNU/Linux をインストールして使う場合も、 そのまま適用できるはず。

i8042 のバグ対策を行なってタッチパッドを認識させる

他のいくつかのノートPC (dynabook Satellite P10, Thinkpad R31, Lifebook P7010, Dell XPS M1530 など) と同じく、 OLEVIA X10A-1160 (確認していないが、おそらく SOTEC C101 も同様) のキーボード/マウス コントローラ i8042 互換チップにはバグがある。 OLEVIA X10A-1160 の場合、カーネル起動時に以下のようなログを出力する:

PNP: PS/2 Controller [PNP0303:PS2K,PNP0f13:PS2M] at 0x60,0x64 irq 1,12
i8042.c: Detected active multiplexing controller, rev 1.1.
serio: i8042 KBD port at 0x60,0x64 irq 1
serio: i8042 AUX0 port at 0x60,0x64 irq 12
serio: i8042 AUX1 port at 0x60,0x64 irq 12
serio: i8042 AUX2 port at 0x60,0x64 irq 12
serio: i8042 AUX3 port at 0x60,0x64 irq 12
        ...(中略)...
input: PS/2 Generic Mouse as /devices/platform/i8042/serio4/input/input9
psmouse.c: Failed to enable mouse on isa0060/serio4

存在しないはずの外付けポート (AUX0~3) コントローラ (multiplexing controller) を認識してしまうようだ。 このため、 タッチパッド (SynPS/2 Synaptics TouchPad) が使えなくなってしまう。 この問題は、 カーネルパラメータに i8042.nomux=1 を追加することによって回避できる。 例えば GRUB の設定ファイル /boot/grub/menu.lst に、

title           Ubuntu 8.04.1, kernel 2.6.24-23-generic
root            (hd0,0)
kernel          /boot/vmlinuz-2.6.24-23-generic root=UUID=(省略) ro quiet splash vga=789 i8042.nomux=1
initrd          /boot/initrd.img-2.6.24-23-generic
quiet

といった感じで 「i8042.nomux=1」 を追加すればよい。 Linux を再起動すると、

PNP: PS/2 Controller [PNP0303:PS2K,PNP0f13:PS2M] at 0x60,0x64 irq 1,12
serio: i8042 KBD port at 0x60,0x64 irq 1
serio: i8042 AUX port at 0x60,0x64 irq 12
        ...(中略)...
Synaptics Touchpad, model: 1, fw: 5.10, id: 0x258eb1, caps: 0xa04711/0x0
input: SynPS/2 Synaptics TouchPad as /devices/platform/i8042/serio1/input/input7

などと出力し、 無事 SynPS/2 Synaptics TouchPad が認識できた。

なお Linux は、 i8042 にバグを持つ PC で問題を回避できるよう、 PC のブラックリストを持っている。 すなわち linux/drivers/input/serio/i8042-x86ia64io.h で定義されている配列 i8042_dmi_nomux_table に PC の ID を登録しておくと、 該当する PC では自動的に i8042.nomux=1 が設定される仕掛けだが、 あいにく OLEVIA X10A-1160 は固有の ID を持っていないようだ:

# head /sys/class/dmi/id/{sys_vendor,product_*}
==> /sys/class/dmi/id/sys_vendor <==
 

==> /sys/class/dmi/id/product_name <==
 

==> /sys/class/dmi/id/product_serial <==
Not Applicable

==> /sys/class/dmi/id/product_version <==
Not Applicable

DMI のベンダ名、プロダクト名が共に空白になっている。

無線LAN ドライバ vntwusb をインストールする

OLEVIA X10A-1160 (確認していないが、おそらく SOTEC C101 も同様) は、 無線LAN チップとして VIA Technologies の VT6656 を使用している。 しかし残念ながらこのチップは、 現時点の Linux 標準カーネルではサポートしていない。 したがってドライバをインストールする必要がある。

まず VIA Technologies のサポートページ VT6656 WLAN Linux Driver Source から、 最新版のドライバ vt6656_wlan_linux_v118.zip (1/18 現在) をダウンロードする。 展開して make すれば、 VT6656 用のカーネルモジュール vntwusb.ko が作られる。

% wget http://www.viaarena.com/Driver/vt6656_wlan_linux_v118.zip
--10:19:24--  http://www.viaarena.com/Driver/vt6656_wlan_linux_v118.zip
           => `vt6656_wlan_linux_v118.zip'
Resolving www.viaarena.com... 74.54.151.131
Connecting to www.viaarena.com|74.54.151.131|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 4,483,650 (4.3M) [application/x-zip-compressed]

    0K .......... .......... .......... .......... ..........  1%   68.92 KB/s
        ...(中略)...

% unzip vt6656_wlan_linux_v118.zip
Archive:  vt6656_wlan_linux_v118.zip
   creating: VT6656_WLAN_Linux_V118/
   creating: VT6656_WLAN_Linux_V118/driver/
        ...(中略)...
% cd VT6656_WLAN_Linux_V118/driver
VT6656_WLAN_Linux_V118/driver % make
make -C /lib/modules/2.6.24-23-generic/build SUBDIRS=/home/sengoku/VT6656_WLAN_Linux_V118/driver modules
make[1]: ディレクトリ `/usr/src/linux-headers-2.6.24-23-generic' に入ります
  CC [M]  /home/sengoku/VT6656_WLAN_Linux_V118/driver/main_usb.o
        ...(中略)...
  LD [M]  /home/sengoku/VT6656_WLAN_Linux_V118/driver/vntwusb.ko
make[1]: ディレクトリ `/usr/src/linux-headers-2.6.24-23-generic' から出ます

あとは、make install して modprobe vntwusb するだけ。

VT6656_WLAN_Linux_V118/driver % sudo make install
make -C /lib/modules/2.6.24-23-generic/build SUBDIRS=/home/sengoku/VT6656_WLAN_Linux_V118/driver modules
mkdir -p /lib/modules/2.6.24-23-generic/kernel/drivers/net
install -m 644 -o root vntwusb.ko /lib/modules/2.6.24-23-generic/kernel/drivers/net
/sbin/depmod -a || true
VT6656_WLAN_Linux_V118/driver % sudo modprobe vntwusb

ただし前もって、 カーネルモジュールを make するための環境を整えておく必要がある。 Ubuntu (というか debian) の場合であれば、 module-assistant パッケージと linux-headers パッケージをインストールしておけばよい。 あるいは、 上記 VT6656_WLAN_Linux_V118/driver ディレクトリを、 Linux カーネルソースにコピーしてカーネルを再構築してもよい。

私は、 Linux カーネルソースツリーに、 linux/drivers/net/wireless/vntwusb ディレクトリを作って、 VT6656_WLAN_Linux_V118/driver ディレクトリの内容をコピーし、 linux/drivers/net/wireless/Kconfig および linux/drivers/net/wireless/Makefile に以下のパッチをあてている。

--- linux-2.6.27.11.org/drivers/net/wireless/Kconfig        2008-10-10 07:13:53.000000000 +0900
+++ linux-2.6.27.11/drivers/net/wireless/Kconfig        2009-01-06 14:52:10.459276155 +0900
@@ -702,5 +702,6 @@
 source "drivers/net/wireless/b43legacy/Kconfig"
 source "drivers/net/wireless/zd1211rw/Kconfig"
 source "drivers/net/wireless/rt2x00/Kconfig"
+source "drivers/net/wireless/vntwusb/Kconfig"
 
 endmenu

diff -ur linux-2.6.27.11.org/drivers/net/wireless/Makefile linux-2.6.27.11/drivers/net/wireless/Makefile
--- linux-2.6.27.11.org/drivers/net/wireless/Makefile        2008-10-10 07:13:53.000000000 +0900
+++ linux-2.6.27.11/drivers/net/wireless/Makefile        2009-01-06 14:52:10.491275159 +0900
@@ -58,6 +58,7 @@
 
 obj-$(CONFIG_IWLWIFI)        += iwlwifi/
 obj-$(CONFIG_RT2X00)        += rt2x00/
+obj-$(CONFIG_VNTWUSB)        += vntwusb/
 
 obj-$(CONFIG_P54_COMMON)        += p54/
 

Ubuntu などのディストリビューションのアップデートに頼らずに、 カーネルのバージョンアップを行なっている場合は、 カーネルソースツリーに組み込んでおく方が、 ドライバ込みでカーネルを再構築できるので手間が省ける。

Filed under: ハードウェアの認識と制御 — hiroaki_sengoku @ 08:59
2009年1月8日

wpa_supplicant のバグ: TLS拡張 (TLS Extensions) 対応の OpenSSL と使うと、WPA EAP-TLS が常に失敗する

あけましておめでとうございます。 今年もよろしくお願いします。

自宅の無線LAN を WPA2-EAP (WPA2 エンタープライズ) にして 1ヶ月になるが、 すこぶる快適。 アクセスポイントがエンタープライズモードに対応していなければいけないのと、 RADIUS サーバが必要である上、 EAP-TLS を用いる場合は SSL クライアント証明書を発行する 認証局 (CA) を作る必要まであるので、 自宅LAN での導入にはややハードルが高いが、 いったん導入してしまえば WPA/WPA2 パーソナルより手間がかからない。

WPA/WPA2 パーソナルだと、 秘密のパスワードを全ての無線LAN 端末で共有するので、 端末の台数が増えてくるとどんどん漏洩のリスクが高まる。

自宅LAN でそんなに端末があるのか? という突っ込みが入りそうだが、 格安 NetBook や、 無線LAN 機能付スマートフォンなどを買っていると、 自宅LAN とはいえ、 「エンタープライズ」 的なニーズが出てくる。

WPA2 エンタープライズで認証方式として EAP-TLS を使うと、 無線LAN 端末にはそれぞれ個別の証明書をインポートしておくだけでよく、 万一その端末を紛失しても、 その端末の証明書を無効にするだけで済む。

EAP-TLS には対応機器/OS が多いというメリットもある。 無線LAN 端末として、 Windows VISTA, Windows XP, Ubuntu 8.04 LTS などを使ってみたが、 いずれもあっけないくらい簡単に接続できてしまった。 証明書さえインポートしておけば (Windows ならダブルクリックだけ)、 あとはパスワードを入力しなくてもいいぶん WPA/WPA2 パーソナルより設定が簡単。

既存の OS (Linux の場合はディストリビューション) で無線接続できるようになったので、 次は私が独自に構築した GNU/Linux (いわば my distribution) 上で WPA2 EAP-TLS 接続を試みた。

まず wpa_supplicant 0.5.11 をダウンロードしてコンパイル。 続いて設定ファイルである wpa_supplicant.conf を書く。

network={
        ssid="XXXXXXXXXX"
        key_mgmt=WPA-EAP
        eap=TLS
        identity="olevia"
        ca_cert="/usr/local/ssl/certs/GCD_Root_CA.pem"
        client_cert="/usr/local/ssl/certs/olevia.pem"
        private_key="/usr/local/ssl/private/olevia.pem"
        private_key_passwd=""
}

「ca_cert=」 「client_cert=」 「private_key=」 にそれぞれ CA の公開鍵、端末の公開鍵、端末の秘密鍵のファイル名を指定している。 で、wpa_supplicant を実行。

# wpa_supplicant -i eth1 -c /etc/wpa_supplicant.conf -d -D wext
Initializing interface 'eth1' conf '/etc/wpa_supplicant.conf' driver 'wext' ctrl_interface 'N/A' bridge 'N/A'
Configuration file '/etc/wpa_supplicant.conf' -> '/etc/wpa_supplicant.conf'
Reading configuration file '/etc/wpa_supplicant.conf'
Priority group 0
   id=0 ssid='XXXXXXXXXX'
Initializing interface (2) 'eth1'
EAPOL: SUPP_PAE entering state DISCONNECTED
EAPOL: KEY_RX entering state NO_KEY_RECEIVE
EAPOL: SUPP_BE entering state INITIALIZE
EAP: EAP entering state DISABLED
        ...(中略)...

wpa_supplicant はデバッグモード (-d オプション) にすると大量のログを出力するので動作を追いにくいが、 wpa_supplicant のプログラムは状態遷移機械 (オートマトン) として動作するよう書かれているので、 「EAP: EAP entering state」 の部分を追っていくとよい。 「DISABLED」 と出力されているのが、 その時点におけるオートマトンの状態。

状態遷移機械 (オートマトン) と言ってしまうと、 コンピュータ/プログラムは全てオートマトンなのであるが (^^;)、 プログラミングの方法として状態遷移機械 (state machine) と言うときは、 各状態に名前を付けて、 各状態ごとの動作を (switch 文や if ... else if ... 文などで) 分けて書く方法を指す。

状態には INITIALIZE, DISABLED, IDLE, RECEIVED, GET_METHOD, METHOD, SEND_RESPONSE, DISCARD, IDENTITY, NOTIFICATION, RETRANSMIT, SUCCESS, FAILURE の 13状態がある。 もちろん 「SUCCESS」 が受理状態。 SUCCESS 状態は、 アクセスポイントが接続を許可した状態を意味する。

ところが、ログを追っていくと、

EAP: EAP entering state RECEIVED
EAP: Received EAP-Success
EAP: EAP entering state FAILURE
CTRL-EVENT-EAP-FAILURE EAP authentication failed

FAILURE 状態 (非受理状態) に遷移している (*_*)。当然、接続できず。
その直前に 「Received EAP-Success」 と出ているにもかかわらず!

アクセスポイント側 (正確に言うと RADIUS サーバ) のログを調べてみると、 ちゃんと接続を許可している (EAP-Success を送っているのだから当然だが)。 一体これはどうしたことか?

私がコンパイルした wpa_supplicant に問題があるのかと思って、 この wpa_supplicant を、 既に接続できることが確認済みの Ubuntu 上にコピーして実行してみる。 「Received EAP-Success」 をログの中から探してみると、

EAP: EAP entering state RECEIVED
EAP: Received EAP-Success
EAP: EAP entering state SUCCESS
CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully

ちゃんと SUCCESS 状態に遷移しているし、接続もできた。
同一バイナリなのに、異なる環境 (ディストリビューション) だと、 どうして結果が異なるのか?

どのような可能性が考えられるだろうか? 腕に覚えがあるかたは、 この続きを見ずに (といっても、既にタイトルでネタバレしてしまっているが ^^;) 原因を推測してみてはいかがだろうか?

More...
Filed under: システム構築・運用 — hiroaki_sengoku @ 08:58