こんにちは、ネットワークエンジニアの皆さん。日々のインフラ運用や、オフィス・スマートホームの無線設計、本当にお疲れ様です。
「我が家のリビングから書斎へ移動した途端、Web会議のパケットがピタッと止まる」
「最新のWi-Fi 7ルーターを導入したのに、なぜかスマホが電波の弱い古いアクセスポイント(AP)にしがみつき続ける」
こうした『スティッキーローミング(Sticky Roaming)』問題に頭を悩ませた経験はないでしょうか。仕様書やカタログスペックでは「シームレスなローミング」と謳われていても、実際の現場では、クライアント端末(スマホやノートPC)がどのタイミングでどのAPへハンドオーバーするかは、最終的にクライアント側の気まぐれに委ねられています。
今回は、この無線LANにおける永遠の課題であるローミング問題の深層に切り込みます。IEEE 802.11k/v/rという規格群が無線空間でどのようにパケットをやり取りし、認証のオーバーヘッドを削り取っているのか。その実務的なトラブルシューティング手法と検証アプローチを、シニアエンジニアの視点でお届けします。
—
1. スティッキーローミングのメカニズムと「クライアント主導」の罠
まず大前提として押さえておきたいのは、Wi-Fiのローミングは「アクセスポイント側が強制的に引っペがして移動させるものではなく、クライアント側が自発的に判断して決めるもの」だという点です。
AP側から見れば、いくら電波強度(RSSI)が低下している端末に対して「こっちの強いAPに来いよ」と心の中で叫んでいても、クライアントが「いや、まだ今のAPの電波が聞こえるからここにいる!」と判断(スティッキー状態)していれば、通信は劣化し続けます。
クライアント側の判断基準(RSSI閾値)
多くのOS(iOS、Android、Windows、macOS)は、接続先の RSSI が特定の閾値(一般的には -70 dBm から -75 dBm 付近)を下回ると、周囲のチャネルスキャンを開始します。そして、より良好なBSSID(AP)を見つけた場合にローミング処理(Reassociation)をトリガーします。
しかし、この「スキャンして移行先を決めるまでのタイムラグ」と「従来の4-Way Handshakeによる再認証の遅延」が、リアルタイムアプリケーション(VoIPやWeb会議)においてパケットロスや切断を引き起こす主犯となります。
—
2. IEEE 802.11k / v / r がもたらす救済策
この泥臭いローミング問題をスマートに解決するために策定されたのが、いわゆる「Fast Roaming」を構成する3つのIEEE 802.11規格です。現場で設計・運用するにあたり、それぞれの役割を正しく理解しておく必要があります。
- IEEE 802.11k (Radio Resource Measurement):
周囲の電波環境や近隣APのリスト(Neighbor Report)をクライアントに提供します。これにより、クライアントは無駄な全チャネルスキャンを行う必要がなくなります。
- IEEE 802.11v (BSS Transition Management):
AP側からクライアントに対して「負荷分散のために、あっちのAPへ移動してくれないか?」と提案(Transition Request)を送る機能です。クライアントがスティッキーになっている場合でも、強力な後押しになります。
- IEEE 802.11r (Fast BSS Transition / FT):
認証の高速化です。通常、別APへローミングする際はフル認証(EAPまたはPSKによる4-Way Handshake)をやり直すため、数十〜数百ミリ秒の通信断が発生します。FTでは、事前に鍵導出の階層を準備しておくことで、この認証プロセスを劇的に短縮します。
—
3. 802.11r (FT) の再認証時間短縮効果をパケットキャプチャで検証する
百聞は一見にしかず。それでは、IEEE 802.11rが有効な環境と無効な環境で、ローミング時のパケット挙動がどう変わるのかを検証してみましょう。
通常のWPA2/WPA3-PSK環境におけるローミングでは、Reassociation Request/Responseの後に、再度 4-Way Handshake(EAPOL-Key のやり取り)が走ります。
[クライアント] [新しいAP]
|--- (Reassociation Request) --->|
|<-- (Reassociation Response) ---|
|<-- (EAPOL-Key Msg 1/4) --------| <-- ここで時間がかかる
|--- (EAPOL-Key Msg 2/4) ------->|
|<-- (EAPOL-Key Msg 3/4) --------|
|--- (EAPOL-Key Msg 4/4) ------->|
これに対して、IEEE 802.11r(FT over-the-air)が有効な場合、認証情報(FT Information Element)がReassociationフレームの中にカプセル化され、一撃で認証が完了します。
パケット検証の現場視点(Wiresharkでの確認ポイント)
無線パケットアナライザー(OmniPeekやWiresharkのモニターモード)でキャプチャを取得した際、以下のポイントを確認します。
1. Reassociation Request/Responseフレームの中身
- 「Mobility Domain Information Element (MDIE)」が含まれているか。
- 「Fast BSS Transition Information Element (FTIE)」が存在し、R0KH-ID / R1KH-IDが正しくやり取りされているか。
2. ハンドシェイクの有無
- 従来の4-Way Handshakeパケットが消え、Reassociationの直後にデータパケット(
QoS Dataなど)が流れているか。
これにより、認証遅延を数ミリ秒レベル(体感でゼロに近い状態)まで削り込むことが可能です。
—
4. 実務での設定・トラブルシューティング Tips
ここからは、実際にエンタープライズ向けAP(Cisco Catalyst、Aruba、あるいはOpenWrtベースのカスタム環境など)や家庭用メッシュWi-Fiを構築・運用する際の、現場で使える具体的な設定とデバッグ手法を解説します。
設定例:OpenWrt (hostapd) における 802.11r / k / v の有効化
オープンソースのルーターファームウェアであるOpenWrtの無線設定ファイル (/etc/config/wireless) を例に、Fast Roaming関連のパラメータ設定を見てみましょう。
config wifi-device 'radio0'
option type 'mac80211'
option channel '36'
option hwmode '11a'
option htmode 'VHT80'
# 5GHz帯の基本設定
config wifi-iface 'default_radio0'
option device 'radio0'
option network 'lan'
option mode 'ap'
option ssid 'Enterprise-Lab-Wi-Fi'
option encryption 'psk2+ccmp'
option key 'super_secret_network_key'
# --- IEEE 802.11r (Fast Transition) の設定 ---
option ieee80211r '1'
option mobility_domain '4f54' # 16進数のモビリティドメインID (同一モビリティドメイン内でローミング可能)
option FT_over_ds '0' # 0: Over-the-Air, 1: Over-the-DS
option ft_psk_generate_local '1' # PSK環境でのローカル鍵生成を有効化
# --- IEEE 802.11k (Radio Resource Measurement) ---
option rrm '1'
option ieee80211v '1' # 802.11v BSS Transition Management の有効化
option bss_transition '1'
エンジニア向けの重要な解説ポイント:
mobility_domain: ローミングを許可するAP群の間で、このID(例:4f54)は必ず一致させておく必要があります。異なるID間ではFTローミングは機能しません。FT_over_ds:0(Over-the-Air)は無線区間で直接AP間認証を行い、1(Over-the-DS)は有線バックボーン経由で認証メッセージを中継します。通常の無線AP構成であれば0がパフォーマンス上有利なケースが多いですが、メッシュのトポロジによっては1が安定することもあります。
—
5. クライアント側の挙動デバッグ(Pythonによる死活監視スクリプト)
「ローミング時にパケットロスが何発発生しているのか」を定量的に測定するため、筆者が現場でよく使う軽量なPythonスクリプトを共有します。これをローミング移動しながら実行し、RTT(往復遅延)やドロップの傾向を可視化します。
import time
import subprocess
import platform
import sys
def ping_host(target="1.1.1.1", interval=0.1):
"""
高頻度(100ms間隔)でPingを打ち続け、ローミング時のパケットロスと遅延を測定する
"""
print(f"[*] 監視を開始します (ターゲット: {target}, 間隔: {interval}秒)")
print("[*] 終了するには Ctrl+C を押してください。\n")
# OSに応じたpingコマンドのフラグ調整
param = "-n" if platform.system().lower() == "windows" else "-c"
seq = 0
try:
while True:
start_time = time.time()
# タイムアウトを短めに設定 (0.1秒)
command = ["ping", param, "1", "-W", "100", target] if platform.system().lower() != "windows" \
else ["ping", param, "1", "-w", "100", target]
result = subprocess.run(command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
elapsed = (time.time() - start_time) * 1000
timestamp = time.strftime("%H:%M:%S", time.localtime())
if result.returncode == 0:
print(f"[{timestamp}] Seq {seq:5d}: 応答成功 (約 {elapsed:.1f} ms)")
else:
print(f"[{timestamp}] Seq {seq:5d}: ⚠️ パケットロス検出! (ローミング発生の可能性)")
seq += 1
time.sleep(interval)
except KeyboardInterrupt:
print("\n[*] 監視を終了しました。")
if __name__ == "__main__":
target_ip = sys.argv[1] if len(sys.argv) > 1 else "1.1.1.1"
ping_host(target_ip)
このスクリプトを走らせながら自宅やオフィスの廊下を歩いてみると、どの地点でAPが切り替わり、その瞬間に何パケット欠落するのかが手に取るように分かります。もしここで数秒間の不通時間が続くようであれば、802.11rの設定不備や、チャネル幅(20MHz/40MHz/80MHz)の干渉を疑うべきです。
—
おわりに
Wi-Fiのローミング問題は、無線という「目に見えない媒体」を相手にするがゆえに、勘や経験則だけに頼りがちです。しかし、IEEE 802.11k/v/rの仕様を正確に理解し、パケットキャプチャやスクリプトによる実測値をベースに検証を行えば、原因の特定は決して難しくありません。
「なんとなくつながる」から「意図通りにシームレスにつながる」インフラへ。今回の知見が、あなたのネットワークをより強靭にする一助となれば幸いです。
それでは、また次の技術でお会いしましょう!
コメント