はじめに
主に車載ネットワークのEhternet関連についての記事。
https://www.simulationroom999.com/blog/in-vehicle-network-backnumber/
登場人物
博識フクロウのフクさん
イラストACにて公開の「kino_k」さんのイラストを使用しています。
https://www.ac-illust.com/main/profile.php?id=iKciwKA9&area=1
エンジニア歴8年の太郎くん
イラストACにて公開の「しのみ」さんのイラストを使用しています。
https://www.ac-illust.com/main/profile.php?id=uCKphAW2&area=1
書籍とか
ぶっちゃけ車載ネットワーク関連の書籍は少ない。
車両の事情とPCネットワーク関連の情報の合わせ技で日頃から情報収集する以外の手段が無いのが実状。
BLF
- 上司からの恒例の無茶振り。
- BLFというVector社の独自フォーマットにEthernetの収録情報が入っているらしい。
- ダメ元でいろいろ調べていくことに。
- BLFの仕様書はCANoeのインストールフォルダから発掘。
- 仕様書は全部で6個。
- 「CAN_and_General_BLF_Format.pdf」が基本的な仕様。
- その他は各物理層向けの追加仕様。
- BLF仕様のライセンスについて確認。
- 一言でまとめると「Vectorが一切責任を負わないことを条件に好きにしていいよ」。
- BLF仕様の概要説明。
- オブジェクトヘッダとオブジェクトの仕様がポイントとなる。
- BLFのオブジェクトヘッダの説明。
- CANオブジェクトの説明。
- Ethernetオブジェクトの説明。
- BLFのオブジェクトヘッダを追っかけた。
- 仕様書にないオブジェクトタイプが存在。
- 実データ部は圧縮か、暗号化されている様子。
- BLFの中身はzlibで圧縮されたもの。
- オブジェクトは”LOBJ”というシグネチャを先頭に始まるルールのもよう。
- BLF解凍用の言語はPythonを採用
- zlibとか配列の制御が楽ちん。
- zlib解凍後のデータはまだ全貌がつかめていないので、改めて再調査予定。
- BLFのオブジェクト抽出とzlib解凍のPythonコードを書いた。
- オブジェクト抽出に起因するコードが支配的。
- zlib解凍後のファイルも解析が必要。
- BLF内のオブジェクトの頭出しは”LOBJ”という文字列であり、先頭の方はxmlによるメタ情報が埋まっていた。
- よって、今回はテキストエディタで無理やりBLFを開いてみた。
- メタ情報はOS,CANoe,回線,使用しているデータベースファイルなどが記載されている。
- zlib解凍済みBLFをバイナリエディタで覗いて各フレームを抽出。
- CANフレーム抽出。
- Ethernetフレームを抽出。
- mObjectTypeと仕様書上のオブジェクト構成はオブジェクトヘッダのサイズから雰囲気で特定。
- フレーム抽出&テキスト化のプログラミング言語はPythonを使用予定。
- zlib解凍済みBLFをCANフレーム、Ethernetフレーム単位に分解するPythonコードを書いた。
- mObjectType:0x56 → CANフレーム。
- mObjectType:0x78 → Ethernetフレーム。
- BLFをフレーム単位にテキスト出力した。
- CANフレーム解説。
- Ethernetフレーム解説。
- Ethernetフレームはマルチキャストになっている。
EthernetFrame
- 3つの通信方式を説明。
- ユニキャスト。
- ブロードキャスト。
- マルチキャスト。
- ブロードキャストとマルチキャストは似て非なるもの。
- ブロードキャストは同一ネットワーク。
- マルチキャストは同一グループ。
- Ethernetフレーム説明。
- IPヘッダ説明。
- ブロードキャスト、マルチキャストを理解するには上記二つの理解が重要。
- IPアドレスは、サブネットマスクでネットワーク部とホスト部に分かれる。
- ブロードキャストアドレスは2種類存在。
- リミテッドブロードキャストアドレス。
- ディレクティッドブロードキャストアドレス。
- マルチキャストはMACアドレスでグループが確定する。
- ただし、MACアドレスはSocketLibrary等で制御できないため、IPアドレスとの紐づけルールが存在。
- ユニキャスト、マルチキャスト、ブロードキャストのまとめ。
- ノードで見た場合。
- MACアドレスで見た場合。
- IPアドレスで見た場合。
通信方式 | MAC | IP | 範囲 | 備考 |
---|---|---|---|---|
ユニキャスト | 送信先はノード個別のMAC | ノード個別のIP | 単体 | |
ブロードキャスト | 送信先はFF-FF-FF-FF-FF-FF | 255.255.255.255 | 全体 | 別ネットワークを指定することも可能。192.168.0.255/24等 |
マルチキャスト | 送信先は01-00-5E-[グループIPの一部] | グループIP | 特定の複数 | MACにグループIPの一部を含めることでデータリンク層のレベルで送信先を決定。 |
IPフラグメント
- BLFのEthernetFrameを分解してみた。
- UDPだった。
- データ長がEthernetFrameの最大長を超えていた。
- つまり、IPフラグメント仕様が使われている。
- IPフラグメントに着目してEthernetFrameを確認。
- IPヘッダのフラグでIPフラグメントになるかどうかが決定する。
- 断片化位置で全体のどこのデータかが分かるようになっている。
- 2フレーム目を確認。
- これもIPヘッダのフラグは継続。
- 断片化位置の値は、その値×8が実際のデータオフセット位置となる。
- よって、IPフラグメントは8byte境界の仕様が暗黙的に発生する。
- IPフラグメント最後のEthernetFrameを確認。
- IPヘッダの継続フラグが0。
- 残りのサイズが埋まっている。
- 断片化位置が8byte境界になっていればよいので、パケット末端は8byte境界である必要はない。
- 真面目に結合していくとメンドクサイ。
- 次回以降にちょっとした裏技をやる予定。
プロトコルスタック
- プロトコルスタックの説明。
- 組み込み向けのプロトコルスタックを使用すると何かできるかも?
- オープンソースなプロトコルスタック3つを紹介。
- TINET。
- uIP。
- lwIP。
- lwIPを使用予定。
- lwIPは軽量プロトコルスタック。
- 数十[Kbyte]のRAMと約40[Kbyte]のROM。
- 対応プロトコル多数。
- APIはバークレーSocketタイプ。
- アドオン済みアプリケーションがある。
- HTTP(S)とかSTMP(S)とか。
lwIP
- lwIPにBLFのEthernetFrameを入れるシムテム構成を描いた。
- EthernetInputが受信割り込み時に呼び出す関数。
- 事前にUDP Socketを生成する必要がある。
- 事前にマルチキャストグループに参加する必要がある。
- lwIPのソースコードを入手。
- 開発環境はVisualStudio 2017 express。
- community版だといろいろ利用する上で制約があるので。
- lwIPをPC上でビルドした。
- 修正はarch/cc.hに起因するもの。
- arch/cc.hはコンパイラ依存部の辻褄合わせようのヘッダファイル。
- lwIPの制御手順概要を説明。
- 一般的なSocketと違ってネットワーク関連の初期化も必要。
- IPフラグメントはIP層の仕様に組み込まれているので利用側は特に何もしなくてOK。
- lwIPの初期化関数はlwip_init。
- lwip_initの内部は#if~#endifで必要最低限の初期化が可能。
- include/lwip/opt.hで使用する機能の有効/無効の切り替えができる。
- lwIPのネットワークインターフェースの追加について説明。
- netif_add関数を使用する。
- 引数はIPアドレス、ネットマスク等のIP層の他、データリンク層由来のものもある。
- データリンク層初期化関数はコールバック関数initに渡す。
- netif_add関数を使用する。
- lwIPのマルチキャストグループの参加について説明。
- igmp_joingroup_netif関数を使用。
- 上記関数を呼び出すとIGMPでグループ参加を通知するためのパケットが送信される。
- lwIPのネットワークインターフェースの初期化について説明。
- netif_set_up関数を使用する。
- ネットワークインターフェースをUP状態にするもの。
- 実は呼ばなくてもOKな疑惑があるが、流儀としては呼び出しておくべき。
- netif_set_up関数を使用する。
- lwIPのリンクアップについて説明。
- アップ(UP)が物理層。
- リンクアップ(link-up)がデータリンク層。
- 余談的にリンクローカルアドレスの説明。
- lwIPのUDP Socket生成についての説明。
- 内部で固定長メモリプールでメモリ領域の確保をしている。
- 固定長メモリプールはITRON等のRTOSにも実装されている高速な動的メモリ取得解放のロジック。
- 公開されているITRON4.0仕様を参照してみるのも良い。
- Bindという用語について調べた。
- lwIPのIPアドレス、ポートへのBindについて説明。
- IP_ANY_TYPEを指定すると、全インターフェースに紐づく。
- ポート0を指定すると自動割り付け。
- 送信用Socketの場合に利用されることが多い。
- Bindという用語について調べた。
- lwIPのIPアドレス、ポートへのBindについて説明。
- IP_ANY_TYPEを指定すると、全インターフェースに紐づく。
- ポート0を指定すると自動割り付け。
- 送信用Socketの場合に利用されることが多い。
- lwIPのEthnertFrameの疑似受信について説明。
- ethernet_input関数を呼び出すだけだが引数が曲者。
- pbufという連結リストのバッファにパケットをコピーする必要がある。
- ethernet_input関数を呼び出すだけだが引数が曲者。
lwIP疑似受信
- lwIP疑似受信用のソースコード。
- 詳細は前回までのlwIPのAPI説明を参照願う。
- lwIP疑似受信は成功。
- IPフラグメントに対応していた。
- IPフラグメントにまつわる特殊な動作があるらしい。
- IPフラグメントはEthernetFrameの順番が入れ替わっても結合してくれる仕様。
- lwIPが対応しているかは不明。
- IPフラグメントの受信フレーム順を変える疑似受信コード作成。
- 渡す受信フレームの順番を入れ替えるだけ。
- 組み込み系として、この仕様は重くないか?
- 重いが、割とよくある話でもあり、lwIPも対応しているであろうと楽観視。
- IPフラグメントの受信フレーム順番入れ替えをしても受信した。
- ログも確認したが、最終フレームで打ち切ってることはしていない。
- IPフラグメントの順番入れ替えの判定のソースコードと該当関数説明。
- Ethnertフレームを連結リストで管理。
- 連結は常にソートされた状態。
- 開始位置と完了位置を持ってパケットの完全性を評価している。
生パケット送信
- Windowsから生のEthernetFrame送受信をするはめになった。
- 生Socketが扱えないWindowsだとやや困難。
- パケットアナライザ、ネットワークアナライザ、スニファというものが存在。
- Wiresharkが有名。
- Wiresharkは生のEthernetFrameを読み取れる。
pcapというライブラリを使用して実現しているらしい。
- pcapはpacket capture関連のAPI仕様。
- Windows向けのpcapは以下3種類。
- WinPcap:Windows10では不安定。
- Win10Pcap:Windows10でも問題無いが開発が止まっている。
- npcap:Wiresharkでも使用されており実績がある。
npcap
- npcapはnmapプロジェクトから落としてこれる。
- Wiresharkをインストールしても一緒に入る。
- npcap-SDKを持ってくる。
- ビルド環境はVisual Studio 2015 express or communityを想定しているようだんが、Visual Studio 2017 expressでも多分平気。
- サンプルソリューションの中のpktdump_exでパケットモニタをしてみた。
- ネットワークインターフェース名とIDの紐づけを調べる必要がある。
- ipconfigでMACアドレス確認。
- getmacでMACアドレスとID確認。
- 上記二つの情報から紐づけを確認。
- パケット取得で使用したAPIを列挙。
- pcap_findalldevs:ネットワークデバイスのリストの構築。
- pcap_open_live:ネットワーク上のパケットを見るためにパケットキャプチャハンドルを取得。
- pcap_next_ex:次のパケットを読み込んで、成功/失敗の指示を返す。
- npcapのネットワークデバイスのリストの構築のAPIの説明。
- pcap_findalldevsを使用する。
- リストは連結リストでfor文で回して走査できる。
- ネットワーク上のパケットを見るためにパケットキャプチャハンドルを取得のAPIの説明
- open/close系のAPI。
- パケット長はとりあえず最大の65535。
- プロミスキャスもとりあえず有効でOK。
- タイムアウトはそこそこの値を入れておいた方が処理効率が上がる。
- スレッドの性格。
- 各種エラー。
- 次のパケットを読み込むAPIについて説明。
- 多重ポインタが使われている。
- 参照先をAPI内で設定してもらう割と一般的な使い方。
- 今回からnpcapでEthernetFrameの送信。
- サンプルのsendpackを使用。
- デバイスリストから選択できるように一部修正。
- パケット送信のサンプルのsendpackを動作させた。
- pktdump_exとWiresharkでキャプチャ。
- 想定通りのパケットが送出されていた。
- パケット送信APIについて説明。
- 送信バッファ、送信サイズを指定するだけのシンプルな物。
- 特に特殊なことは無い。
- ホントに無い。
lwIP+npcap
- 太郎くん思い付きのシミュレーション構成。
- lwIPの下にnpcapを置くことでプロトコルスタックのシミュレーション。
- 目的はlwIPにアドオン済みのHTTPサーバの動作。
- 中間の動作確認用にpingことICMPも搭載しておく。
- ネットワークシミュレーションのビルド環境は実績のあるVisualStudio 2017 express。
- lwIPとnpcap-SDKも入手しておく。
- デバッグ/検証をし易くするようWiresharkもインストールしておく。
- lwIPのソースコード修正。
- 以前のlwIP疑似受信の時の情報を流用。
- VisualStudio 2017でlwIPのソリューションとプロジェクトを作成。
- フィルタをフォルダ構成に合わせておくと見やすいかも。
- lwIPの受信インターフェースは以前やった。
- 送信インターフェースはやってなかった。
- netifのlinkoutputってメンバ変数に登録するコールバック関数が送信インターフェース。
- ただし、連結リストのバッファを渡す必要がある。
- 連結リスト復習。
- 送信データを連結リストからリニアバッファに変換するコード作成。
- エラーコードも調べて適切なエラーハンドリング実施。
- npcap初期化コードに必要なAPI説明。
- pcap_findalldevs。
- pcap_open_live。
- ※ 両方とも以前説明済み。
- npcap初期化コードを作成。
- サンプルコードのpcap_next_exをベースに抜き出してきた。
- pcap_next_ex以外にキャプチャ用のAPIが存在。
- pcap_loop関数。
- pcap_loopを使用したサンプルはudpdump。
- udpのみをフィルタしてキャプチャするサンプルプログラム。
- 今回は使用しないが、今後フィルタすることもあるえるため、こちらの実装方法を採用。
- pcap_datalinkはリンクタイプ取得API。
- リンクタイプはbpf.hで定義されている。
- 引数はpcap_open_liveで取得したディスクリプタを渡すのみ。
- Ethernetの場合は”DLT_EN10MB”が戻り値となる。
- npcapのフィルタ文字列コンパイルAPIについて説明。
- フィルタ文字列仕様はtcpdumpのフィルタ書式と一緒。
- tcpdumpのフィルタ書式はかなり数が多いため、良く使用しそうなものに限定。
- MACアドレスフィルタ。
- IPアドレスフィルタ。
- IPアドレとポートをフィルタ。
- npcapのパケットフィルタ有効化APIについて説明。
- pcap_compileとpcap_setfilterはセットで使うAPI。
- 文字列で式を指定し、計測前にバイナリ変換する方式は割と一般的。
- センサ電圧を物理値(圧力とか流量とか)にリアルタイムで変換する場合など。
- npcapのキャプチャ処理APIについて説明。
- pcap_next_exの方が分かり易いが、結局はpcap_loopと同等の実装になり易いため最初からpcap_loopにしておくのもあり。
- pcap_loopにはコンテキスト維持用にユーザパラメータを渡すことができる。
- HTTPサーバ機能の下にaltcp(application layered TCP connection API)が存在。
- HTTPサーバの初期化コードを呼べばHTTPサーバとして動作する。
- httpd_initの中でlisten待ち。
- accept時に受信、エラー、ポーリング、送信のコールバック設定。
- lwIP PCシミュレーション用のコードを書いた。
- pcapとlwIPそれぞれの初期化処理を実施。
- pcapのデバイスリストとディスクリプタ関連。
- lwIPのネットワークインターフェース関連。
- その後にアプリ層のHTTPサーバの初期化。
- 最後にpcapの受信処理ループ。
- lwIP起動直後に送信しているパケットがある。
- GARPとIGMP。
- IGMPはマルチキャストグループ参加。
- GARPはARPの一種だが、聞かれて答えるタイプではなく能動的に宣言するタイプ。
- 組み込み機器とかはPCのように柔軟な対応ができないことが多いため、早々にGARPでIPアドレスを宣言することが多い。
- lwIPに向けてpingを打ってみた。
- 問題無く応答。
- pingレスポンスの直前にlwIPからARP要求発生。
- GARPによりPCからlwIPは見えているが、lwIPからPCが見えていないため。
- ARPテーブルにlwIPのIPアドレスとMACアドレスが登録されているのを確認。
- lwIP PCシミュレーションでHTTPサーバを動作させた。
- ブラウザのアドレスバーにIPアドレスを打ち込む感じ。
- lwIPのサンプルページが表示される。
- 本質的な失敗は存在しない。
- うまくいかない方法を発見できたと言える。
100base-T1
- IEEEの説明をした。
- 電気情報系の技術標準化機関。
- IEEE802の説明をした。
- ローカルエリアネットワーク関連規格。
- IEEE802.3。
- Ethernet関連規格。
- IEEE802.3u。
- 100Base-TX。
- IEEE802.3bw。
- 100base-T1(車載Ethernet)
- 100base-T1とBroadR-Reachは同じもの。
- 違いはコンプライアンステストの詳細度。
- 車載ネットワークはハーネスの重さがキモとなり要シールドレス。
- CAN/CAN-FDがその課題を解決していたが、映像を扱うシステムでは転送速度が不足。
- そこで100Base-T1、BroadR-Reachの登場。
- 100Base-T1の詳細仕様説明。
- 比較対象として100base-TXも。
- 仕様名はIEEE802.3bw。
- データ転送レートは100Mbps。
- 変調方式はPAM3。
- 3レベル2bitが論理3bit分。
- MII、クロックの話と合わせると効能が分かる。
- 100Base-T1の詳細仕様のうち、MIIについて説明。
- MIIはMedia-Independent Interfaceの略。
- 基本的には100Base-TX仕様で語られているインターフェース仕様。
- 100Base-T1は4B/3B/2Tという変換プロセスが入る。
- 通信をする上でエッジは重要。
- 100Base-T1の詳細仕様(クロック、ハーネス最大長、伝送方式)説明。
- クロックは3bitを3レベル2bitにすることから66.7MHz。
- ハーネス長は対ノイズ性と衝突検知精度を確保するため短め。(15[m])。
- 伝送方式はシングルツイストペア。
- 100Base-T1の詳細仕様まとめ。
- とりあえず、ざっと表でまとめた。
- 100Base-T1をPCから制御する方法。
- 専用デバイスを使用するパターン。
- ネットワークインターフェースに化けるパターン。
- 100Base-T1がCANに取って代わるのは考えずらい。
コメント