このエントリに記載している方法は危険かもしれません。実施される方は自己責任で行ってください。
USB_DEVICEマクロを使ってIdVendor,IdProductの指定をしている
("__mod_usb_device_table"のmatch_flagsが0x03)
場合はこの方法で問題ないとおもわれますが、match_flagsの値がそれ以外の場合は十分でないようです。
hitoさんによる此方の投稿を参照してください。
https://forums.ubuntulinux.jp/viewtopic.php?pid=60947#p60947
Ubuntuでインストール後にすぐ使用できるコマンドだけでカーネルモジュールを直接書き換えて
USB無線LANクライアントを認識させる方法を下記に記述します。
(readelf,od,strings,perlおよびテキストエディタを使用)
成功例が一つ(rt2870sta)だけであるため、別のモジュールで有効であるか不明ですが、
どうしても有線LANの接続が確保できない場合やビルド環境の導入が困難である場合に
試してみる価値はあると思います。
デフォルトで認識されてしまうので例はJauntyで実施しました。
カーネルは2.6.28-11-generic。GW-USMicroNのIDは2019:ed14です。
これだけでは心もとないので、Lucidで2019:ed14を取り除いたモジュールをビルドし、同じ要領を実施しました。
これも認識、接続に成功しています。
前提条件は対象のUSB無線LANクライアントが使用しているチップを駆動するカーネルモジュールが既知で
あること。(そしてデフォルトでモジュールが存在するが、子機が認識されないこと。)
USB無線LAN子機のidVendor,idProductのペアがmodules.alias,modules.usbmapに
存在しない場合、下記の方法で接続できる可能性があります。
●1.前置き(きっかけ)
●2.readelf,od,stringsで収集する情報
●3.書き換え作業
●4.モジュールの認識
●1.前置き(きっかけ)
きっかけはdepmodコマンドで更新される[/lib/modules/$(uname-r)/]のmodules.* にlsbusbで出力されるidVendor,idProductと同じ値を見つけたことに始まります。
当該の値が含まれているファイルはmodules.aliasとmodules.usbmapで下記のようなものでした。
■modules.aliasの内容
# Aliases extracted from modules themselves. alias rt3070sta rt2870sta alias usb:v0411p015Dd*dc*dsc*dp*ic*isc*ip* rt2870sta alias usb:v1737p0077d*dc*dsc*dp*ic*isc*ip* rt2870sta
■modules.usbmapの内容
# usb module match_flags idVendor idProduct bcdDevice_lo bcdDevice_hi bDeviceClass bDeviceSubClass bDeviceProtocol bInterfaceClass bInterfaceSubClass bInterfaceProtocol driver_info rt2870sta 0x0003 0x148f 0x2770 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x0 rt2870sta 0x0003 0x1737 0x0071 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x0 rt2870sta 0x0003 0x1737 0x0070 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x0 rt2870sta 0x0003 0x148f 0x2870 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x0
これらの値はそれぞれdepmodコマンドがモジュールのファイルから読み出したものです。
depmodのソースから調べてみると下記の部分から取得していました。
■modules.aliasの元情報
モジュールの ".modinfo" セクションを元に作成されています。
$ readelf -p .modinfo モジュールファイルのパスで簡単に見ることができます。
モジュールのソースにおていこの情報は
linux/module.hで定義されているMODULE_ALIASマクロを使って宣言されているようです。
#define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias) #define MODULE_DEVICE_TABLE(type,name) \ MODULE_GENERIC_TABLE(type##_device,name)
■modules.usbmapの元情報
モジュールの"__mod_usb_device_table"シンボルに格納されています。
バイナリなので容易には見ることができません。
depmodを含むmodule-init-toolsのソースパッケージではtables.hで
その構造とサイズを定義しています。
(usb_device_id構造体、サイズはUSB_DEVICE_SIZE32,USB_DEVICE_SIZE64)
モジュールのソースにおていこの情報は
linux/usb.hで定義されている下記のマクロを使って宣言されているようです。
#define USB_DEVICE(vend,prod) \ .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \ .idVendor = (vend), \ .idProduct = (prod)
Ralinkのドライバ(RT2870_LinuxSTA_V2.3.0.0.tar.tar.bz2)では
USB_DEVICEを使用しているソースからMODULE_ALIASを使用するソースを
自動で生成しているようです。
●2.readelf,od,stringsで収集する情報
書き換え対象のidVendor,idProductとそのモジュール上の位置を知る必要があります。 ここでは"__mod_usb_device_table"シンボルの先頭のIDを対象にします。 そして対応する".modinfo"のエントリのオフセットを探します。
■モジュールの退避、バックアップの作成
対象モジュールを作業ディレクトリにコピーし、念のためバックアップを作っておきます。
$ sudo cp -p /lib/modules/$(uname -r)/kernel/drivers/staging/rt2870/rt2870sta.ko ./ $ TRG_MOD=./rt2870sta.ko $ sudo cp -p $TRG_MOD ${TRG_MOD}.org
■"__mod_usb_device_table"の最初のエントリの位置と値の取得
まずreadelfコマンドで"__mod_usb_device_table"シンボルがが格納されている
セクションとその先頭からのオフセット、サイズを取得します。
コマンドの実行結果から25番目のセクションに格納されていて、
先頭からのオフセットが16進で0x4140、サイズが1220Byteであることが分かります。
(先頭だけを対象にするのでサイズは特に必要ありません。)
$ TRG_MOD=/lib/modules/2.6.28-11-generic/kernel/drivers/staging/rt2870/rt2870sta.ko $ readelf -s $TRG_MOD | sed -ne '1,3p;/__mod_usb_device_table/p;' Symbol table '.symtab' contains 1267 entries: Num: Value Size Type Bind Vis Ndx Name 555: 00004140 1220 OBJECT GLOBAL DEFAULT 25 __mod_usb_device_table
25番目のセクションを探します。".data"セクションです。
ファイルの先頭から16進で0x6c980で始まっていることが分かります。
(別のモジュールで試してみると番号[Nr]はモジュールによって違いますが、
セクション名は".data"でした。基本的に".data"セクションを探せばよさそうです。)
$ readelf -S $TRG_MOD | sed -ne '1,4p;/\[25\]/p;' There are 35 section headers, starting at offset 0x73830: Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [25] .data PROGBITS 00000000 06c980 004694 00 WA 0 0 32
開始アドレスを計算してodコマンドで内容を表示します。
1レコードが20Byteで先頭5項目はunsigned shortであることが分かっているので
(depmodのソースtable.h参照)
odのオプションに -N 20 --width=20 -t x2 を指定します。
上位バイトと下位バイトが逆になって表示されます。
そこからunsigned shortを2つ分(計4byte)を書き換え対象にします。
$ perl -e 'print 0x4140 + 0x6c980 ,"\n"' 461504 $ od -j 461504 -N 20 -v -A d -t x2 --width=20 $TRG_MOD 0461504 0003 148f 2770 0000 0000 0000 0000 0000 0000 0000
■modules.aliasの元になる情報の書き換え位置
次にmodules.aliasの元になる情報の書き換え位置を調べます。
これは文字列なのでstringsコマンドに-tdオプションを指定することで
比較的簡単に調べることができます。
十進でファイルの先頭からのオフセット438048Byte,長さ20Byteを書き換えます。
("alias=usb:v148Fp2770" を "alias=usb:v2019pED14"へ)
$ strings -td $TRG_MOD | grep -i -e 148f.2770 438048 alias=usb:v148Fp2770d*dc*dsc*dp*ic*isc*ip*
●3.書き換え作業
perlを使って書き換えを行ないます。
■"__mod_usb_device_table"の先頭書き換え
write_vp.plというスクリプトを書きました。
ネット接続不可の状況でも、その場ですぐにかけるような内容です。
書換え後のidVendor,idProductは直書きです。
引数は対象ファイルとオフセットです。
### スクリプト内容の表示 $ cat ./write_vp.pl #!/usr/bin/perl if($#ARGV != 1){ print STDERR "usage $0 filepath offset\n"; } my($file) = shift; my($offset) = shift; open FH, "+< " . $file or die "$!:$file"; seek(FH, $offset, 0); my($buf) = pack "SS", 0x2019, 0xed14; syswrite(FH, $buf, 4) or die "$!"; ### 実行 $ sudo ./write_vp.pl $TRG_MOD 461506 ### 確認 $ od -j 461504 -N 20 -v -A d -t x2 --width=20 $TRG_MOD 0461504 0003 2019 ed14 0000 0000 0000 0000 0000 0000 0000
■".modinfo"セクションの書き換え
write_alias.plというスクリプトを書きました。
write_vp.plと同じく短いものです。
### スクリプト内容の表示 $ cat ./write_alias.pl #!/usr/bin/perl if($#ARGV != 1){ print STDERR "usage $0 filepath offset\n"; } my($file) = shift; my($offset) = shift; open FH, "+< " . $file or die "$!:$file"; seek(FH, $offset, 0); syswrite(FH,"alias=usb:v2019pED14",20); seek(FH, $offset, 0); sysread(FH,$buf,20); print $buf,"\n"; ### 実行 $ sudo ./write_alias.pl $TRG_MOD 438048 alias=usb:v2019pED14 ### 確認 $ strings -td $TRG_MOD | grep -e 2019.ED14 438048 alias=usb:v2019pED14d*dc*dsc*dp*ic*isc*ip*
●4.モジュールの認識
モジュールを正式な位置に書き戻してdepmodで依存情報を更新し、modprobeでモジュールを読み込みます。
$ sudo cp $TRG_MOD /lib/modules/$(uname -r)/kernel/drivers/staging/rt2870/ $ sudo depmod -a $(uname -r) $ sudo modprobe rt2870sta
あとはNetworkManagerで認証関係の設定を行えば接続できるはずです。
0 件のコメント:
コメントを投稿