おうちで簡単SFPハック
SFP/SFP+のハードウェアについて
SFP/SFP+のハードウェアについては、以下の資料に詳細が記されています。
ftp://ftp.seagate.com/sff/INF-8074.PDF
ftp://ftp.seagate.com/sff/SFF-8419.PDF
Hackの為に必要な情報としては以下の通り。
- 最低限必要な配線
- VccT/VccE - Vcc(3.3V)
- VeeT/VeeR - GND
- MOD-DEF1 - I2C SCL (I2Cのクロック)
- MOD-DEF2 - I2C SDA (I2Cのデータ
- I2C
- I2Cのプロトコル
- Atmel AT24C01Aに代表されるI2C EEPROM互換のInterface
- I2Cアドレスは0x50と0x51
- 0x50: モジュールの定義情報を含むEEPROM(ハック対象)
- 0x51: DDM等、デバイスの状態が反映されるEEPROM状のインターフェイス
- SFPによってはこの中にパスワードを受け付けるアドレスがあり、そこに適切なパスワードを書き込む事によって0x50の書き込みが可能になるものがある。
- 概ね0x7bからの4バイトがパスワード空間、Finisarのデフォルトは[0x00, 0x00, 0x00, 0x00]
- I2Cは3.3Vロジックなので、Raspberry Piとは直結可能だが、Arduino Unoとは直結不可能なので注意
- Arduino Pro Mini 3.3V等、3.3Vロジックのマイコンとなら接続可能
- SCL, SDAともにプルアップが必要なので忘れずに
- I2Cのプロトコル
デバイスの接続
上記の情報を元に、何らかのコンピュータとSFPを接続する必要がある。SFPコネクタを入手して直接配線する事も可能ではあるが、専用の基板無しでSFPコネクタに半田付けを行うのは至難の業であるので、ここでは、入手及び配線が容易な以下のデバイスを使用する。
- マイコン
- Raspberry Pi(モデルは何でもOK)
- Raspberry Piでi2cを使えるように設定しておくこと。(raspi-configで可能)
- i2c-toolsを入れておくこと。
- Raspberry Pi(モデルは何でもOK)
- SFPスロット
Cisco TwinGig Converter CVR-X2-SFP
これらを以下のように接続する。プルアップ抵抗はCVR-X2-SFPに内蔵されているため直結でOK!I
接続の確認
上記手順の通りSFPスロットとRaspberry Piを接続した後、電源を起動し、SFPスロットにSFPを挿入する。以下のコマンドで、SFPが正しく認識されることを確認する。
$ sudo i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: 50 51 -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
正しく認識されていると、上記のように0x50番地に何かが接続されていると表示される。0x51については前述の通りDDM用であるが、デバイスによっては表示されないこともある(1000BASE-TのSFPや中華製の安物等)。
データの吸い出し
SFPが正しく認識されていることを確認できたら、続いてデータの吸い出しを行う。I2C EEPROMは非常に単純なプロトコルなので、以下のコマンドで容易に吸い出しが可能である。
$ sudo i2cdump -y 1 0x50 No size specified (using byte-data access) 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef 00: 03 04 07 00 00 00 01 20 40 0c 01 01 0c 00 00 00 ???...? @????... 10: 37 1e 00 00 46 49 4e 49 53 41 52 20 43 4f 52 50 7?..FINISAR CORP 20: 2e 20 20 20 00 00 90 65 46 54 52 4a 2d 38 35 31 . ..?eFTRJ-851 30: 39 2d 37 44 2d 4a 55 4e 00 00 00 00 03 52 00 12 9-7D-JUN....?R.? 40: 00 12 00 00 48 35 46 30 51 30 35 20 20 20 20 20 .?..H5F0Q05 50: 20 20 20 20 30 34 30 34 31 39 20 20 68 10 00 c5 040419 h?.? 60: 37 34 30 2d 30 30 37 33 32 36 20 52 45 56 20 30 740-007326 REV 0 70: 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1............... 80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ 90: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
さて、吸い出したこのデータ、そのままでは読みにくいのでHuman-readableな形に変換したいところであるが、手で行うのは非常に面倒である。
そこで作成したParserがあるので、こちらを使ってみると、以下のようになる。このプログラムにはI2Cの読込/書込のプログラムも含まれているため、もはやi2ctoolsは用済みである。
$ cd ruby-libsfp/examples $ ruby read.rb raw data: 0304070000000120400c01010c000000371e000046494e4953415220434f52502e202020000090654654524a2d383531392d37442d4a554e000000000352001200120000483546305130352020202020202020203034303431392020681000c53734302d30303733323620524556203031000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff #<SFP::EEPROM:0x6504f0 @br=:BR_1200M, @br_max=0, @br_min=0, @cc_base=18, @cc_ext=197, @connector=:LC, @date_code="040419", @diagnostic_monitoring_type= [:DDM, :INTERNAL_CALIBRATED, :RECEIVED_POWER_MEASUREMENT_AVERAGE], @encoding=:ENC_8B10B, @enhanced_options=[:SOFT_RX_LOS], @ext_identifier=4, @identifier=:SFP, @length_copper=0, @length_mm500_10m=55, @length_mm500_om3_10m=0, @length_mm625_10m=30, @length_sm_100m=0, @length_sm_km=0, @options=[:TX_DISABLE, :LOSS_OF_SIGNAL], @rate_identifier=0, @sff_8472_compliance=0, @transciever= [:GE_SX, :FC_LINK_I, :FC_TXT_SN, :FC_TXM_M6, :FC_TXM_M5, :FC_SPEED_100M], @transciever2=0, @used_for_dwdm_modules=0, @vendor_name="FINISAR CORP.", @vendor_oui=[0, 144, 101], @vendor_pn="FTRJ-8519-7D-JUN", @vendor_rev="", @vendor_sn="H5F0Q05", @vendor_specific= "740-007326 REV 01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", @wavelength=850> Base CC is valid? : false Ext CC is valid? : true Expected Base CC: 146 Expected Ext CC: 197
非常に読みすい(?)ですね。
raw data: 0304...というところが生データになるので、ここはバックアップしておきましょう。
書き換え
さて、読み込んだならば書き換えねばなるまい。ということで、実際に書き換えてみましょう。
irbで上記のライブラリを読み込み、OUIとベンダ名を書き換えてみます。
新しいベンダ名は"JITAKURACK", OUIはC0-A8-FE(192, 168, 254)とします。特に意味は無いです。
$ cd ruby-libsfp $ irb # ライブラリの読み込み irb(main):001:0> require './lib/sfp/rw.rb' => true irb(main):002:0> require './lib/sfp/eeprom.rb' => true # SFP R/Wライブラリの初期化 irb(main):003:0> rw = SFP::RW.new => #<SFP::RW:0xca85a0 @path="/dev/i2c-1", @addr=80> # SFP R/Wで読み込んだ情報を元にSFP EEPROMライブラリのインスタンスを生成 irb(main):004:0> sfp = SFP::EEPROM.new(rw.read) => #<SFP::EEPROM:0xf92328 @identifier=:SFP, @ext_identifier=4, @connector=:LC, @transciever=[:GE_SX, :FC_LINK_I, :FC_TXT_SN, :FC_TXM_M6, :FC_TXM_M5, :FC_SPEED_100M], @encoding=:ENC_8B10B, @br=:BR_1200M, @rate_identifier=0, @length_sm_km=0, @length_sm_100m=0, @length_mm500_10m=55, @length_mm625_10m=30, @length_copper=0, @length_mm500_om3_10m=0, @vendor_name="FINISAR CORP.", @transciever2=0, @vendor_oui=[0, 144, 101], @vendor_pn="FTRJ-8519-7D-JUN", @vendor_rev="", @wavelength=850, @used_for_dwdm_modules=0, @options=[:TX_DISABLE, :LOSS_OF_SIGNAL], @br_max=0, @br_min=0, @vendor_sn="H5F0Q05", @date_code="040419", @diagnostic_monitoring_type=[:DDM, :INTERNAL_CALIBRATED, :RECEIVED_POWER_MEASUREMENT_AVERAGE], @enhanced_options=[:SOFT_RX_LOS], @sff_8472_compliance=0, @vendor_specific="740-007326 REV 01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", @cc_base=18, @cc_ext=197> # オリジナルのベンダ名とOUIを確認 irb(main):005:0> sfp.vendor_name => "FINISAR CORP." irb(main):006:0> sfp.vendor_oui => [0, 144, 101] # ベンダ名とOUIの書き換え irb(main):007:0> sfp.vendor_name = "JITAKURACK" => "JITAKURACK" irb(main):008:0> sfp.vendor_oui = [ 0xC0, 0xA8, 0xFE ] => [192, 168, 254] # 書き換え後の情報確認 irb(main):009:0> sfp => #<SFP::EEPROM:0xf92328 @identifier=:SFP, @ext_identifier=4, @connector=:LC, @transciever=[:GE_SX, :FC_LINK_I, :FC_TXT_SN, :FC_TXM_M6, :FC_TXM_M5, :FC_SPEED_100M], @encoding=:ENC_8B10B, @br=:BR_1200M, @rate_identifier=0, @length_sm_km=0, @length_sm_100m=0, @length_mm500_10m=55, @length_mm625_10m=30, @length_copper=0, @length_mm500_om3_10m=0, @vendor_name="JITAKURACK", @transciever2=0, @vendor_oui=[192, 168, 254], @vendor_pn="FTRJ-8519-7D-JUN", @vendor_rev="", @wavelength=850, @used_for_dwdm_modules=0, @options=[:TX_DISABLE, :LOSS_OF_SIGNAL], @br_max=0, @br_min=0, @vendor_sn="H5F0Q05", @date_code="040419", @diagnostic_monitoring_type=[:DDM, :INTERNAL_CALIBRATED, :RECEIVED_POWER_MEASUREMENT_AVERAGE], @enhanced_options=[:SOFT_RX_LOS], @sff_8472_compliance=0, @vendor_specific="740-007326 REV 01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", @cc_base=18, @cc_ext=197> # 書き換え後のデータをSFPに書き込み irb(main):010:0> rw.write(sfp.to_hex) => 9 # 比較用に再度SFPの情報を読み込み irb(main):011:0> sfp2 = SFP::EEPROM.new(rw.read) => #<SFP::EEPROM:0xf41fb8 @identifier=:SFP, @ext_identifier=4, @connector=:LC, @transciever=[:GE_SX, :FC_LINK_I, :FC_TXT_SN, :FC_TXM_M6, :FC_TXM_M5, :FC_SPEED_100M], @encoding=:ENC_8B10B, @br=:BR_1200M, @rate_identifier=0, @length_sm_km=0, @length_sm_100m=0, @length_mm500_10m=55, @length_mm625_10m=30, @length_copper=0, @length_mm500_om3_10m=0, @vendor_name="JITAKURACK", @transciever2=0, @vendor_oui=[192, 168, 254], @vendor_pn="FTRJ-8519-7D-JUN", @vendor_rev="", @wavelength=850, @used_for_dwdm_modules=0, @options=[:TX_DISABLE, :LOSS_OF_SIGNAL], @br_max=0, @br_min=0, @vendor_sn="H5F0Q05", @date_code="040419", @diagnostic_monitoring_type=[:DDM, :INTERNAL_CALIBRATED, :RECEIVED_POWER_MEASUREMENT_AVERAGE], @enhanced_options=[:SOFT_RX_LOS], @sff_8472_compliance=0, @vendor_specific="740-007326 REV 01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", @cc_base=190, @cc_ext=197> # 作成したデータとSFPのEEPROMの内容が一致していることを確認 irb(main):012:0> sfp.to_hex == sfp2.to_hex => true irb(main):013:0>
こんな感じです。ライブラリの使い方はexamples/以下のファイルを見ていただけると大体分かるかと思います。
それでは、Let's enjoy hack life!
0 コメント