# 帳票設計書 35-usbdump

## 概要

本ドキュメントは、FreeBSDのusbdumpコマンドが生成するUSBトラフィックダンプレポートの設計を記述する。usbdumpはBPF（Berkeley Packet Filter）を使用してUSBバス上のパケットをキャプチャし、転送情報をレポートするCLIユーティリティである。

### 本帳票の処理概要

usbdumpコマンドは、/dev/bpfデバイスを通じてUSBバスインターフェース（usbus*）からUSB転送パケットをキャプチャし、タイムスタンプ・アドレス・エンドポイント・転送タイプ・速度・フレーム情報・エラーステータスなどをリアルタイムまたはファイルから読み取ってレポート出力する。

**業務上の目的・背景**：USBデバイスのデバッグやドライバ開発において、USBバス上の実際の転送内容を詳細に確認することは不可欠である。usbdumpはカーネルのUSBサブシステムとBPFフィルタを統合し、効率的なUSBトラフィック分析を可能にする。

**帳票の利用シーン**：USBデバイスドライバのデバッグ、USB機器の通信プロトコル解析、USBパフォーマンス問題の調査、USBセキュリティ監査（BadUSB検出等）に利用される。

**主要な出力内容**：
1. パケットタイムスタンプ（HH:MM:SS.微秒）
2. USBバス番号、デバイスアドレス
3. 転送方向（SUBM/DONE）、転送タイプ（CTRL/ISOC/BULK/INTR）
4. エンドポイント番号、速度、フレーム数、データ長、インターバル
5. エラーステータス（DONE時のみ）
6. フレーム詳細（-v以上：READ/WRITE、バイト数、hexdump）
7. 転送フラグ（-vv以上）、転送ステータス（-vvv以上）
8. キャプチャ統計（終了時：captured/received/dropped）

**帳票の出力タイミング**：usbdumpコマンド実行中にリアルタイムで出力。Ctrl+C（SIGINT）で終了し統計を表示。

**帳票の利用者**：デバイスドライバ開発者、USBハードウェアエンジニア、セキュリティ研究者

## 帳票種別

リアルタイムストリーム / パケットダンプレポート

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| N/A | CLIターミナル | N/A | `usbdump [options]` コマンド実行 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | テキスト（標準出力）/ バイナリ（-w/-bオプション） |
| 用紙サイズ | N/A（ターミナル出力） |
| 向き | N/A |
| ファイル名 | -w: 指定ファイル（USBキャプチャ形式）/ -b: 指定ファイル（rawバイナリ） |
| 出力方法 | 標準出力（stdout）/ ファイル出力 |
| 文字コード | ASCII |

### PDF固有設定

該当なし

### Excel固有設定

該当なし

## 帳票レイアウト

### レイアウト概要

```
┌──────────────────────────────────────────────────────────────────────────┐
│  パケット行: HH:MM:SS.UUUUUU usbusB.D DIR-TYPE-EP=XXXX,SPD=X,...      │
│  フレーム行:  frame[0] READ/WRITE N bytes (verbose >= 1)               │
│  hexdump:    0000  XX XX XX XX ... |............| (verbose >= 1)       │
│  flags:      flags 0xXXX <FLAG1|FLAG2|...> (verbose >= 2)             │
│  status:     status 0xXXX <STATUS1|STATUS2|...> (verbose >= 3)        │
├──────────────────────────────────────────────────────────────────────────┤
│  統計（終了時）:                                                         │
│  N packets captured                                                     │
│  N packets received by filter                                           │
│  N packets dropped by kernel                                            │
└──────────────────────────────────────────────────────────────────────────┘
```

### ヘッダー部

ヘッダー行は出力されない。

### 明細部

#### パケット行（verbose >= 0, print_apacket関数 行459-572）

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | timestamp | タイムスタンプ | header_32.ts_sec/ts_usec | "%H:%M:%S.%06ld" |
| 2 | bus.addr | バス番号.デバイスアドレス | up_busunit, up_address | "usbus%d.%d" |
| 3 | direction | 転送方向 | up_type | "SUBM" or "DONE" |
| 4 | xfertype | 転送タイプ | up_xfertype | "CTRL"/"ISOC"/"BULK"/"INTR" |
| 5 | endpoint | エンドポイント番号 | up_endpoint | "EP=%08x" |
| 6 | speed | USB速度 | up_speed | "SPD=FULL/HIGH/LOW/VARI/SUPER" |
| 7 | nframes | フレーム数 | up_frames | "NFR=%d" |
| 8 | datalen | データ長 | up_totlen計算 | "SLEN=%d" |
| 9 | interval | インターバル | up_interval | "IVAL=%d" |
| 10 | error | エラー（DONE時のみ） | up_error | "ERR=エラー文字列" |

#### フレーム詳細行（verbose >= 1, 行520-567）

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | frame_idx | フレームインデックス | ループ変数 | "frame[%u]" |
| 2 | direction | READ/WRITE | framehdr.flags & USBPF_FRAMEFLAG_READ | "READ" or "WRITE" |
| 3 | length | フレーム長 | framehdr.length | "%d bytes" |
| 4 | hexdump | 16進ダンプ | フレームデータ | hexdump形式 |

### フッター部（終了時統計、行980-983）

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | captured | キャプチャパケット数 | pkt_captured | "%d packets captured" |
| 2 | received | フィルタ受信パケット数 | bpf_stat.bs_recv | "%d packets received by filter" |
| 3 | dropped | カーネルドロップ数 | bpf_stat.bs_drop | "%d packets dropped by kernel" |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| -i interface | 対象USBバスインターフェース（デフォルト: usbus0） | No |
| -d ugenB[.D[.E]] | バス/デバイス/エンドポイント指定 | No |
| -f unit[.endpoint] | デバイス/エンドポイントフィルタ | No |
| -s snaplen | スナップショットバイト数（デフォルト: 192） | No |
| -r file | ファイルからの読み取り | No |

### ソート順

パケット到着順（時系列）

### 改ページ条件

改ページなし（リアルタイムストリーム）

## データベース参照仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| /dev/bpf | BPFデバイスからのUSBパケット読取 | ioctl(BIOCSETIF) |
| キャプチャファイル | -rオプションで読み取り | usbcap_filehdr検証 |

### テーブル別参照項目詳細

#### struct usbpf_pkthdr（USBパケットヘッダー）

| 参照項目 | 帳票項目との対応 | 取得条件 | 備考 |
|---------|----------------|---------|------|
| up_busunit | bus | BPFからの読取 | リトルエンディアン→ホストエンディアン変換 |
| up_address | addr | BPFからの読取 | |
| up_type | direction | BPFからの読取 | USBPF_XFERTAP_SUBMIT or DONE |
| up_xfertype | xfertype | BPFからの読取 | UE_CONTROL/ISOCHRONOUS/BULK/INTERRUPT |
| up_endpoint | endpoint | BPFからの読取 | |
| up_speed | speed | BPFからの読取 | USB_SPEED_FULL/HIGH/LOW/VARIABLE/SUPER |
| up_frames | nframes | BPFからの読取 | |
| up_totlen | datalen計算 | BPFからの読取 | |
| up_interval | interval | BPFからの読取 | |
| up_error | error | BPFからの読取 | USB_ERR_*定数 |
| up_flags | flags | BPFからの読取 | verbose >= 2で表示 |
| up_status | status | BPFからの読取 | verbose >= 3で表示 |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| datalen(SLEN) | up_totlen - USBPF_HDR_LEN - (USBPF_FRAME_HDR_LEN * up_frames) | N/A | 行512-513 |
| エンディアン変換 | le32toh(各フィールド) | N/A | 行483-492 |
| BPFフィルタ生成 | BPFインストラクション配列構築 | N/A | make_filter関数 行185-261 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[コマンド実行] --> B[getoptによるオプション解析]
    B --> C{-rオプション?}
    C -->|Yes| D[init_rfile: キャプチャファイル読取初期化]
    C -->|No| E[BPFデバイスオープン]
    D --> F[read_file: ファイル読取ループ]
    E --> G[BPFバッファサイズ設定]
    G --> H[BIOCSETIF: インターフェース設定]
    H --> I[make_filter: BPFフィルタ設定]
    I --> J[BIOCSRTIMEOUT: タイムアウト設定]
    J --> K[signal(SIGINT)]
    K --> L[do_loop: キャプチャループ]
    F --> M[print_packets]
    L --> N{-wオプション?}
    N -->|Yes| O[write_packets: ファイル書き出し]
    N -->|No| M
    O --> M
    M --> P[print_apacket: パケット出力]
    P --> Q{verbose >= 1?}
    Q -->|Yes| R[フレーム詳細 + hexdump]
    Q -->|No| S[パケット行のみ]
    L -->|SIGINT| T[BIOCGSTATS: 統計取得]
    T --> U[統計出力]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| BPFオープン失敗 | /dev/bpfがオープンできない | "Could not open BPF device" | 権限確認 |
| BPFバージョン不一致 | カーネルBPFバージョン不一致 | "Kernel BPF filter out of date" | カーネル更新 |
| バッファサイズ失敗 | 適切なバッファサイズが見つからない | "No buffer size worked" | - |
| ファイルマジック不正 | キャプチャファイルのマジック値不正 | "Invalid magic field" | ファイル形式確認 |
| バージョン不正 | キャプチャファイルのバージョン不正 | "Invalid major/minor version" | ファイル形式確認 |
| メモリ不足 | malloc失敗 | "Out of memory" | システムリソース確認 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | リアルタイムストリーム（制限なし） |
| 目標出力時間 | リアルタイム（パケット到着即時出力） |
| 同時出力数上限 | 1インスタンス/インターフェース |
| BPFバッファサイズ | 64KB〜USBPF_HDR_LEN（段階的縮小） |

## セキュリティ考慮事項

- /dev/bpfデバイスへのアクセスにはroot権限またはbpfグループの権限が必要
- USBトラフィックにはキーボード入力やストレージデータなどの機密情報が含まれる可能性がある
- キャプチャファイル（-w）にはUSB転送の生データが保存されるため、適切なアクセス制御が必要

## 備考

- snapshot長のデフォルトは192バイト（行804）
- -wオプションまたは-bオプション指定時はverboseが1段階下がる（行917-918）
- キャプチャファイル形式はバージョン0.3（uf.major=0, uf.minor=3）
- BPFフィルタはunit/endpointの組み合わせで動的生成される（make_filter関数）
- -uオプションでstdout/stderrのバッファリングを無効化

---

## コードリーディングガイド

本帳票を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | usbdump.c | `usr.sbin/usbdump/usbdump.c` | 行71-75: struct usb_filt（フィルタ条件） |
| 1-2 | usbdump.c | `usr.sbin/usbdump/usbdump.c` | 行77-88: struct usbcap（キャプチャコンテキスト） |
| 1-3 | usbdump.c | `usr.sbin/usbdump/usbdump.c` | 行90-107: struct usbcap_filehdr, struct header_32（ファイル・パケットヘッダー） |
| 1-4 | usbdump.c | `usr.sbin/usbdump/usbdump.c` | 行118-165: エラー文字列/転送タイプ/速度テーブル |

#### Step 2: エントリーポイント（main）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | usbdump.c | `usr.sbin/usbdump/usbdump.c` | 行795-995: main関数 |

**主要処理フロー**:
1. **行815-899**: getoptによるオプション解析（b/d/h/i/r/s/u/v/w/f）
2. **行920-923**: -rモード時のファイル読取処理
3. **行925-964**: BPFデバイスのセットアップ（オープン/バッファ/フィルタ/タイムアウト）
4. **行974**: do_loopによるキャプチャループ開始
5. **行976-983**: 終了後の統計出力

#### Step 3: パケット出力処理（print_apacket）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | usbdump.c | `usr.sbin/usbdump/usbdump.c` | 行459-572: print_apacket関数 |

**主要処理フロー**:
- **行483-492**: リトルエンディアン→ホストエンディアン変換
- **行494-495**: フィルタマッチング
- **行503-517**: パケット概要行の出力
- **行520-567**: フレーム詳細とhexdump出力（verbose >= 1）
- **行568-571**: flags/status出力（verbose >= 2/3）

### プログラム呼び出し階層図

```
main() [usbdump.c:795]
    |
    +-- getopt() [オプション解析]
    +-- add_filter() [フィルタ追加]
    +-- init_rfile() / init_wfile() [ファイルI/O初期化]
    |
    +-- [BPFセットアップ]
    |       +-- open("/dev/bpf")
    |       +-- ioctl(BIOCSBLEN/BIOCSETIF/BIOCSETF/BIOCSRTIMEOUT)
    |       +-- make_filter() [BPFフィルタ生成]
    |
    +-- do_loop() [usbdump.c:690-716]
    |       +-- read(bpf_fd) [パケット読取]
    |       +-- fix_packets() [エンディアン変換]
    |       +-- write_packets() [-wオプション時]
    |       +-- print_packets() [usbdump.c:614-645]
    |              +-- print_apacket() [usbdump.c:459-572]
    |                     +-- match_filter() [フィルタ判定]
    |                     +-- localtime/strftime [タイムスタンプ]
    |                     +-- usb_xferstr/usb_speedstr/usb_errstr [文字列変換]
    |                     +-- hexdump() [16進ダンプ]
    |                     +-- print_flags() / print_status()
    |
    +-- read_file() [-rオプション時]
    |       +-- print_packets()
    |
    +-- ioctl(BIOCGSTATS) [統計取得]
    +-- printf() [統計出力]
```

### データフロー図

```
[入力]                       [処理]                         [出力]

/dev/bpf ──────────> read() [BPFバッファ]             ──> raw packets
                          |                                  |
USB bus (usbus*) ──> BPFフィルタ適用                    ──> filtered packets
                          |                                  |
filtered packets ──> fix_packets() [エンディアン変換]   ──> normalized packets
                          |                                  |
normalized ────────> print_apacket()                   ──> 標準出力（テキスト）
                          |
                    +──> write_packets() [-w]           ──> キャプチャファイル
                    +──> write(bfd) [-b]                ──> rawバイナリファイル
                          |
キャプチャファイル ──> read_file() [-r]                  ──> print_packets()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| usbdump.c | `usr.sbin/usbdump/usbdump.c` | ソース | メインプログラム（全機能を単一ファイルに実装） |
| Makefile | `usr.sbin/usbdump/Makefile` | 設定 | ビルド設定 |
| usb_pf.h | `sys/dev/usb/usb_pf.h` | ヘッダ | USB BPFプロトコル定義（usbpf_pkthdr, usbpf_framehdr） |
| usb.h | `sys/dev/usb/usb.h` | ヘッダ | USB定数定義（USB_ERR_*, USB_SPEED_*） |
| usbdi.h | `sys/dev/usb/usbdi.h` | ヘッダ | USB転送タイプ定義（UE_CONTROL等） |
| bpf.h | `sys/net/bpf.h` | ヘッダ | BPFインターフェース定義 |
