カーネル/VM Advent Calendar 2013 6日目 「802.11 in the 9 World」

カーネル/VM Advent Calendar 2013 6日目 「802.11 in the 9 World」

ほぼ備忘録
# 序
|壁|･ω･`)ﾉ ﾔｧ 802.11的なデムパと毎日楽しくシャドーボクシングしながらｷｬｯｷｬｳﾌﾌしている今日この頃なn_kaneです

こうも毎日、見えない敵と戦ってると**「ｱｱｯ, 9なコードを読んで癒やされよう」**という気持ちが抑えがたいものに
なってくるのは、人間として自然なことではないでしょうか。しばらくご無沙汰になっているなら尚更というものです。

そんな中、「あっ、そういえば 9 は無線LAN対応してるのかな？」とか思いついて読み始めたのが今回の記事のはじまりです。

## まずはソース漁り
なにはともあれソースを漁ります。なにも考えず"802.11"とかそれっぽい単語でカーネルのソースが入っている
/sys/src/9あたりgrepしましょう。

するとでてくるではありませんか。wavelan.cとかwavelan.hとか

やぁやぁ、あるじゃあないか。さすがにPlan 9といえどきちんと対応してるんだなぁ！さすが9だ！(棒

デバイスがpcmciaだけ？ 無問題！ドライバかけばなんとかなるんでしょ？
対応デバイス？
```
char* wavenames[] = {
	"WaveLAN/IEEE",
	"TrueMobile 1150",
	"Instant Wireless ; Network PC CARD",
	"Instant Wireless Network PC Card",
	"Avaya Wireless PC Card",
	"AirLancer MC-11",
	"INTERSIL;HFA384x/IEEE;Version 01.02;",
	nil,
};
```
うん、PCカードとかよくわからんのばかりだけどなんとかなるっしょー

## と、そう考えていた時期がありました。
しかし何かがおかしい。BeaconとかAssocとか、それっぽい単語が読めど読めど出てこない。

（＾ω＾ ≡ ＾ω＾）???

そもそもなんで、WiFiとかWirelessLANとかいう名前で無くて**WaveLAN**なんて言うんだろう....

暗雲が立ちこめてきました

## WaveLANェ....
嫌な予感から目を背けながら恐る恐るGoogle先生に聞いてみます。

WaveLAN
http://en.wikipedia.org/wiki/WaveLAN

> Being a proprietary pre-802.11 protocol, it is completely incompatible with the 802.11 standard.

ProximのOrinocoってデバイスの名前はこのあたりからあるんですねぇというｶﾞｯﾃﾝ体験も束の間、
つまるところ、9には、802.11なんて、現代的なものは、ない...

# 破
## ビバ！ plan9front！
失意の中、やはり頼みになるのは[plan9front](https://code.google.com/p/plan9front/)です。
Plan 9 from Bell Labs からforkして独自路線を突っ走りはじめた9frontですが、見ない間に[無線LANのサポートが増えてる](https://code.google.com/p/plan9front/source/browse/sys/src/9/pc/wifi.c)！
やったぞ9front!すごいぞ9front!しかも今度こそちゃんとした802.11スタック!

WiFi とか大層な名前付けちゃって Wi-Fi Alliance からいちゃもんつけられたりしないのかなとか、
アーキテクチャ非依存なんだから sys/src/9/pc じゃなくて sys/src/9/ip の下に
ethermedium.c と並べて wifimedium.c として置けよ etc とか思うところはありますが、
ようやっとこの記事のメインの部分に到達しました。

## inside wifi.c
### いざコードリーディング、とその前に
明らかにソースの行数が小さい....sloccountでwifi.cとwifi.hの長さを合算すると1400行以下です。これはこわい。
ethermedium.c 600行程度とおおまかにあんまり変わりません。

Ethernetも無線LANも、IEEEでそれぞれIEEE802.3、IEEE802.11として仕様が策定されている規格・プロトコルです。
それぞれ仕様書は長大で、印刷して冊子にしたら人を肉塊にできそうな厚みがありますが、Ethernetのソフトウェアから
見た(実用上最低限の)仕様はそこそこシンプルです。一方、無線LANの側は接続・切断の管理から実際の通信等々に至るまで
最低限の通信をするためにそこそこにやることがあります。
ここでは、それがどのくらいまでできているか、というあたりを見ていきたいと思います。

なお参考までに、印刷して凶器としての利用を考えている方は下記をご参照ください。

- IEEE802.3 http://standards.ieee.org/about/get/802/802.3.html
- IEEE802.11 http://standards.ieee.org/getieee802/download/802.11-2012.pdf

さらに参考までに、3万ぐらいだすと物理本が(一部)買えます

## コールグラフ
wifi.cの主要な関数のコールグラフを作ってみるとこんな感じになります。
![wifi9_call.png](http://sakura.glenda9.org/pic/wifi9_call.png "コールグラフ")
一画面で収まるという非情なまでのシンプルさ。
ccmpとかtkipとかencrypt, decryptという文字列が見えたりとで、暗号化・復号化もできそうな感じです。
ここからは大きく三つのパート、通信管理の全体構造、切断接続関連、暗号化関連と分けて中身をさらっと見ていきます。

## 通信関連
ここではざっくりと通信全体の統御をどうしているか、というあたりのお話。
9のネットワークスタックでは"kernel process”なるものを複数立ててそれぞれ特有の処理をさせる、といった形で実装するのが一般的(のように見える..)です。kernel threadっぽいものが動いているというイメージでしょうか。

9のwifiでは以下のカーネルプロセスが動作しています(上記コールグラフの丸囲み関数)。

- wifiproc
- wifoproc
- wifsproc

wifiprocは受信処理用のプロセスです。ドライバ側からフレームが突っ込まれる受信キュー(wifi->iq)の監視、
およびそこからの取り出しを行い、データなら復号化をしたり接続切断等のフレームなら後述する関数に割り振ったり
といったことをおこないます。

wifoprocは送信処理用のプロセスです。これはwifiprocとは逆にEthernet層からの送信キュー(ether->oq)の監視をし、
そこから取り出したethernetフレームを802.11フレームに変えたり、ペイロード部分を暗号化したりした後に、
ドライバに引き渡すところまでの処理を行います。

wifsprocは定期処理を担当するプロセスです。無線LAN(802.11)ではスキャンを主として接続切断等のハンドリングを行い増す。これについては次の節でもう少しふわりと中身を見ていきます。

## 接続切断関連
主にIEEE802.11にてマネジメントフレームと呼ばれるものを処理するのがこの部分になります。
無線という物理で殴ってどうにかならないものの性質上、Ethernetと似た様な感じで
接続や切断をしたりさらには認証といったことをサポートするために、データとは別枠で
管理用のフレームが用意されています。

一般的に、無線LANクライアントと無線LANアクセスポイントの間では、実際にデータの送受信をする前、
したあとに以下の様なやりとりがなされます。

![wifi9_conn.png](http://sakura.glenda9.org/pic/wifi9_conn.png "接続処理")

それぞれの処理を行う関数を上図にマップしてみました。
Linuxのmac80211やBSDのnet80211に飼い慣らされていると、明らかに9のスタックの
非対称なネーミングセンスが(悪い意味で)光りますね..

さて、上図でも分かるとおりいくつかのマネジメントフレームを9の802.11では扱っていません。
主にAPとして動作するに当たり必要なフレームをはき出す機能が欠けています。

とりあえずはクライアントで動かすことが第一なので、こういった形態なのだと思いますが
今後APとしても動いてほしいところですね。

## 暗号化関連
コールグラフにもあるように、暗号化／復号化のロジック自体は一応あるようです。
CCMPとTKIPについてはencrypt/decryptそれぞれ行えるようです。
WEPについて一切言及していないあたりはなかなか男気溢れますね。

ただし現状、UNIX系ではWPA/WPA2をサポートするのに必要となっているhostapd/wpa_supplicantや
OpenBSDのようにin-kernelなこれ相当のモジュールも存在していないのでこのあたりは今後の課題でしょうか。

個人的にはOpenBSD的に、カーネル内の一ファイルシステムとして実装できるといろいろかっちょよさそうです。

## 無線LANドライバ事情
802.11スタックの実装もそこそこ大変ですが、ドライバの方はどうでしょう、主に数的な意味で。
現状、少なくとも以下のデバイスはサポートに含めようとしているようです。

- [Ralink](http://wikidevi.com/wiki/Ralink) : etherrt2860.c (VendorID: 0x1814)
  - RT2890 (DevID: 0x0681)
  - RT2790 (DevID: 0x0781)
  - RT3090 (DevID: 0x3090)
  - AwtRT2890 (DevID: 0x1059, VendorIDでマッチングしてないけど大丈夫なのかな?)
- [Intel](http://wikidevi.com/wiki/Intel) : etheriwl.c (VendorID: 0x8086)
  - WiFi Link 1000 (0x0084)
  - WiFi Link 4965 (0x4229, 0x4230)
  - WiFi Link 5300 AGN (0x4236)
  - Wifi Link 5100 AGN (0x4237)
  - Centrino Advanced-N 6205 (0x0085)
  - Centrino Ultimate-N 6300 (0x422b)
  - Centrino Wireless-N 100 (0x08ae)

Centrino系までカバーできてるからか、Wikideviを見るとそこそこいろんなデバイスが使えそうでなかなか良い感じに見受けられます。あとはAtherosとかサポートしてると、よりよさげな感じですね。

無線LANなのに、ビルドの都合上全てのドライバに"ether"のプレフィクスがついているのはものすごい違和感ありますが...
(結局上位層からはEthernetとおんなじなのでしようが無い)

# 急
あいかわらず独特の略語変数名と突然のマジックナンバーベタ書きなコードでしたが、ひとまずベースの部分は良い感じにできあがっているようです。毎度シンプルなあたりはこころが洗われます。
ひとまずデバドラ書き、hostapd相当の実装、なんで"wifioproc"じゃなくて"wifoproc"なんやというツッコミあたりからいろいろ手を付けていきましょうね、というあたりで今回のお話はおしまいです。