Wireless・のおと

サイレックスの無線LAN 開発者が語る、無線技術についてや製品開発の秘話、技術者向け情報、新しく興味深い話題、サイレックスが提供するサービスや現状などの話題などを配信していきます。

前の記事:「Bluetoothのはなし(3)」へ

Bluetoothのはなし(4)

2012年12月26日 15:00
YS
BlueZ は Linux および Android で動作するオープンソースの Bluetooth プロトコルスタックです。Bluetooth の実装系としては最もポピュラーなもののひとつだと思いますが、BlueZ に関する解説は日本語はもちろん英語でも非常に限られています。今回はこの BlueZ について簡単な解説を行います。

BlueZ について
BlueZ は BlueZ プロジェクト (http://www.bluez.org/) から配布されています。しかし BlueZ のパッケージにドキュメントらしいものは殆ど含まれておらず、BlueZ のサイトにも解説のようなものは殆どありません。BlueZ について技術的に解説したサイトもほとんどありません。「最もポピュラーな実装系」なのに、あまりにドキュメントが貧弱なのは不思議なくらいです。

BlueZ は大きく分けて「カーネルドライバ」「デーモン」「アプリケーション」の3つから構成されます。

bluez-small.jpgBlueZのアーキテクチャ(拡大表示)

カーネルドライバは bluetooth.ko を中心として、hci_uart.ko, hci_usb.ko などの物理層ドライバや rfcomm.ko, sco.ko などのプロトコルドライバを含みます。これらは BlueZ プロジェクトで開発されているものの、bluez.org からは配布されていません。Linux カーネルには(よほど古いものででなければ)標準で含まれていますし、カーネルドライバ単体としては LinuxWireless (http://www.linuxwireless.org) から WiFi ドライバと一緒にパックされた compat-wireless というかたちで配布されています。
bluetooth.ko は HCI ソケットという API (socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI) で作成する)でユーザー空間と通信します。HCI ソケットはチップの動作を直接制御する階層に近く細かい制御ができる反面、簡単なことをする(たとえばリンクキーを交換してペアリングを成立させる)のにいちいち手間がかかるため、アプリケーションから直接操作することはあまり推奨されません。

デーモンは bluetoothd で、これは BlueZ のパッケージに含まれます。bluetoothd はアダプタ毎の設定保存、リンクキーの管理、サービス検索プロトコル(SDP)のデーモン、上位アプリケーションとの通信などを司っています。アプリケーションは D-BUS と呼ばれる API を経由して bluetoothd と通信し、bluetoothd が必要に応じて内部データベースを更新したり、HCI ソケットを使ってチップにコマンドを送ったりします。

アプリケーションはユーザー空間から BlueZ の設定や制御に使うもので、hciconfighcitool がその代表格です。hciconfig は Ethernet や WiFi で言うところの ifconfig や iwconfig に近く、Bluetooth アダプタの起動や停止、動作設定などを行います。hcitool には様々な機能が入っていますが、多用するのは周辺デバイスを検索する inq と scan で、これは WiFi で言うところの iwlist に近い機能です。

BlueZ のパッケージに標準で入っているのは、基本的に以上の3つだけだと考えてください。コンピュータにキーボードやマウスを接続したり、音楽データを Bluetooth スピーカー経由で再生したりするような機能は基本的にサポートされていません。そういった機能は原則として GUI を用いる必要があります。キャラクタベースの BlueZ には、任意のデバイスと PIN を交換してペアリングしする機能すらもサポートされていません。
BlueZ パッケージの test/ ディレクトリの下に雑多なファイル群(C のソースコードと Python スクリプト) があり、例えば simple-agent (Python スクリプト) を使うと限定的な PIN 交換・ペライリングができるとか(※註)、test-input を使うとキーボードからの入力ができる(できなくもない、に近いレベル)とかの動作もできますが、例によってドキュメントらしきものは皆無に近く、使い方はソースコードを読んで解読するしかありません。

※註:古い BlueZ の解説には「passkey-agent を使えば PIN でペアリングできる」と書かれたものもありますが、BlueZ-3.x 時代の話です。4.x に passkey-agent は存在しません。

詳しい事情はわからないのですが、Linux 上における Bluetooth 機能は Gnome などの GUI 上で使うための開発に注力されており、キャラクタコンソール(CUI) での使用はほとんど放棄されているようです。それゆえに「素の」BlueZ は Bluetooth スタックを動かす土台と API の機能しか提供しておらず、ユーザーが操作して何かを利用する機能は殆ど含まれていないようです。D-BUS はもともとウィンドウシステムにおけるメッセージバスとして用意されたもので、bluetoothd の API がパイプや ioctl ではなく D-BUS として用意されているところにも GUI の偏重を感じます。D-BUS は Java や Python などオブジェクト指向の高級言語で記述すると簡単なのですが、ナマの C 言語で D-BUS の API を書くと簡単なこと一つ済ませるのに矢鱈滅鱈構造体とポインタを振り回さなければならないので、組み込み系プログラミングとの相性はあまり良くないと思うのですが...。

GUI 上で使うかぎり、BlueZ の存在は殆ど意識する必要はありません。GUI に付属している Bluetooth マネージャを開けば自動的に Bluetooth アダプタが初期化されますし、ボタンをクリックして必要条件を入力してゆくだけでデバイスがペアリングされ、ドライバが結合されてキーボード、マウス、ヘッドセットなどが Linux システムの一部として動くようになります。

bluez-gui.jpgGnome Bluetooth GUI マネージャ(Ubuntu Linux)

CUI における BlueZ
数少ない BlueZ 標準機能のなかで、割と普通に使える(でも何が便利なのかは判らない)のはシリアルポートエミュレータ rfcomm です。これはクライアントないしサーバとして使うことができ、いずれにせよ udevd と通信して仮想シリアルポート /dev/rfcommX を作成し、そこに対して open/read/write/close あるいや stty などを実行することで、あたかもシリアルポートのように使うことができます。

クライアントとして使う場合
rfcomm connect 00:80:92:12:34:56 5

サーバとして使う場合
rfcomm listen 7

引数の最後につく 5 とか 7 とかの数字は「チャネル番号」と呼ばれ、TCP/IP におけるポート番号のようなものです。ただし rfcomm におけるチャネル番号は 1~30 の範囲に限られます。
rfcomm はシリアルポートプロファイル(SPP)の根幹をなす機能ですが、rfcomm だけでは SPP とは言えません。SPP サーバはサービス検索プロトコル(SDP)に自分の持つ rfcomm のチャネル番号を含めて通知し、SPP クライアントはそれを検出してチャネル番号を自動的に設定しなければなりませんが、「素の」rfcomm は人力でのチャネル指定だからです。

もうひとつ BlueZ に標準で付いてくるのが pand と呼ばれるネットワーク機能です。ただし BlueZ のパッケージをダウンロードして普通に configure; make しただけではビルドされず、configure 時に --enable-pand オプションを付けなければなりません。Linux のパッケージとして標準で pand が付いてくるかどうかはディストリビューションに依存します。
pand もまたサーバとクライアントの機能を持ちます。サーバは正式には GN:Group ad-hoc Network hub または NAP:Network Access Point と呼びます。GN と NAP の違いは、前者は Bluetooth のなかで「閉じた」ネットワークを形成するのに対し、後者は外部へのルーティング機能を持つことです。一方、クライアントは正式には PANU:Personal Area Network User と呼びます。(※註)

※註:この辺の略語の命名センスは CCITT X.25 とか OSI の仕様書を連想させ、いかにも電話屋さんのセンスだなぁと思います。

クライアントとして使う場合
pand --connect 00:80:92:12:34:56

サーバとして使う場合
pand --listen --role GN (または NAP)

接続が成功すれば bnepX という仮想インターフェースが作成され、これに対し ifconfig で IP アドレスを振ったりすることができます。理屈の上では同じ「PAN プロファイル」なのだから Windows の Bluetooth ネットワークに Linux から pand で参加したり、その逆もできるはずなのですが、成功した試しがありません。それどころか Linux 同士でもディストリビューションの組み合わせによって動いたり動かなかったりすることがあり、何だかよくわからないというのが正直なところです。


Bluetooth LE のサポート
新しい版の BlueZ には限定的な Bluetooth LE のサポートが含まれていますが、これまた解説が皆無に近く使うのに苦労させられます。
hciconfig には leadv / noleadv という機能があり、これを使って LE アドバータイズの発信開始・発信停止を指示することができます。ただし、アドバータイズに含める情報の指定が(今のところ)できないので、lescan をかけても MAC アドレスしか見えません(付加情報が "(unknown)" になる)。

LE アドバイターズを開始する
hciconfig -i hci0 leadv

LE アドバータイズを停止する
hciconfig -i hci0 noleadv


hcitool には lescan という機能があり、これを使って LE のアドバータイズを検索表示することができます。

LE デバイスのスキャン(検索パケット送信を伴う)
hcitool lescan

LE デバイスのスキャン(検索パケット送信を伴わない)
hcitool --passive lescan


レガシイ Bluetooth の hcitool scan コマンドの場合、一定時間後にタイムアウトしてプロンプトに帰ってきますが、lescan は ^C で止めない限り永久に検索表示し続けます。

hcotool lescan の実行例
root@emachine:hcitool lescan
LE scan ...
00:80:92:12:34:56 (unknown)
00:80:92:12:34:56 (unknown)


もう少し進んだ LE のサポート機能としては、gatttool と呼ばれるユーザーインターフェースがあります。これはコマンドラインベースで Bluetooth LE (ないしはレガシイ Bluetooth)のアトリビュートを読み書きするツールですが、t が3つも重なるスペルに何とも投げやりなものを感じます。

gatttool を使って、Buffalo 社の BSBT4PT02BK 近接検出カード(LE proximity プロファイル)のプライマリ・サービス情報を取得すると以下のような結果が得られます。

gatttoolの実行例(1)
root@emachine:/home/sasaki/bt# gatttool -b 00:1b:dc:44:08:bb --primary
attr handle = 0x0001, end grp handle = 0x0007 uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle = 0x0008, end grp handle = 0x000a uuid: 00001803-0000-1000-8000-00805f9b34fb
attr handle = 0x000b, end grp handle = 0x000d uuid: 00001802-0000-1000-8000-00805f9b34fb
attr handle = 0x000e, end grp handle = 0x0010 uuid: 00001804-0000-1000-8000-00805f9b34fb
attr handle = 0x0011, end grp handle = 0xffff uuid: 0000180f-0000-1000-8000-00805f9b34fb


uuid 最下位の 16bit 値は GATT の仕様で定められている規定値で、

1800=Generic Access
1803=Link Loss
1802=Immediate Alert
1804=Tx Power
180F=Battery Service

を示しており、このデバイスが持っているプライマリサービス一覧がわかります。GATT にはもう一つ「キャラクタリスティックス」という情報があり、これは SNMP における MIB walk に近い動作をします。

gatttoolの実行例(2)
root@emachine:/home/sasaki/bt# gatttool -b 00:1b:dc:44:08:bb --characteristics
handle = 0x0002, char properties = 0x02, char value handle = 0x0003, uuid = 00002a00-0000-1000-8000-00805f9b34fb
handle = 0x0004, char properties = 0x02, char value handle = 0x0005, uuid = 00002a01-0000-1000-8000-00805f9b34fb
handle = 0x0006, char properties = 0x02, char value handle = 0x0007, uuid = 00002a04-0000-1000-8000-00805f9b34fb
handle = 0x0009, char properties = 0x0a, char value handle = 0x000a, uuid = 00002a06-0000-1000-8000-00805f9b34fb
handle = 0x000c, char properties = 0x04, char value handle = 0x000d, uuid = 00002a06-0000-1000-8000-00805f9b34fb
handle = 0x000f, char properties = 0x02, char value handle = 0x0010, uuid = 00002a07-0000-1000-8000-00805f9b34fb
handle = 0x0012, char properties = 0x02, char value handle = 0x0013, uuid = 00002a19-0000-1000-8000-00805f9b34fb
handle = 0x0014, char properties = 0x02, char value handle = 0x0015, uuid = 00002a1a-0000-1000-8000-00805f9b34fb
handle = 0x0016, char properties = 0x12, char value handle = 0x0017, uuid = 00002a1b-0000-1000-8000-00805f9b34fb
handle = 0x0019, char properties = 0x02, char value handle = 0x001a, uuid = 00002a3a-0000-1000-8000-00805f9b34fb


ここで例えばハンドル 0x0003 を読み出すと、これが文字列 "BSBT4PT02BK" であることがわかります。16bit UUID 値 2a00 は GATT の仕様において DEVICE NAME CHARACTERISTIC と定められているので、このデバイスのデバイス名が「BSBT4PT02BK」であることがわかる...という具合です。

gatttoolの実行例(3)
root@emachine:/home/sasaki/bt# # gatttool -b 00:1b:dc:44:08:bb char-read --handle=0x0003
Characteristic value/descriptor: 42 53 42 54 34 50 54 30 32 42 4b
Device Name = "BSBT4PT02BK"


まとめ
駆け足で BlueZ の解説をやってみましたが、「何が何だか判らない」という感想をお持ちの方も多いと思います。IP ネットワークの一形態である WiFi と異なり Bluetooth はアプリケーションと密接に連動しているので、Bluetooth という無線技術の階層だけを取り出しても何だかよくわからないし、逆にアプリケーション(携帯電話とヘッドセットの無線接続など)から見ると Bluetooth (BlueZ) の存在は影に隠れてしまいます。広大なはずのインターネット上にも、BlueZ についての解説が呆れるほど少ないのはその立ち位置の微妙さと関係しているのかも知れません。



次の記事:「WPAN のはなし」へ

最新の記事

カテゴリ

バックナンバー