Android の Bluetooth PAN の実装を読む

Android の Bluetooth PAN の実装について調べてみました。

対象のソースコードのバージョンは2016年時点のmasterです。

# ネットワークインターフェイスの生成
PANを開始すると、bt-panという名前のnetwork interfaceが生成されます。
ネットワークインターフェイスの生成はBluetoothプロトコルスタックで行っています。

```C:btif/include/btif_pan_internal.h
#define TAP_IF_NAME "bt-pan"
```

```C:btif/co/bta_pan_co.cc
int btpan_tap_open()
{
    struct ifreq ifr;
    int fd, err;
    const char *clonedev = "/dev/tun";

    /* open the clone device */

    if ((fd = open(clonedev, O_RDWR)) < 0)
    {
        BTIF_TRACE_DEBUG("could not open %s, err:%d", clonedev, errno);
        return fd;
    }

    memset(&ifr, 0, sizeof(ifr));
    ifr.ifr_flags = IFF_TAP | IFF_NO_PI;

    strncpy(ifr.ifr_name, TAP_IF_NAME, IFNAMSIZ);

    /* try to create the device */
    if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0)
    {
        BTIF_TRACE_DEBUG("ioctl error:%d, errno:%s", err, strerror(errno));
        close(fd);
        return err;
    }
    if (tap_if_up(TAP_IF_NAME, controller_get_interface()->get_address()) == 0)
    {
        int flags = fcntl(fd, F_GETFL, 0);
        fcntl(fd, F_SETFL, flags | O_NONBLOCK);
        return fd;
    }
    BTIF_TRACE_ERROR("can not bring up tap interface:%s", TAP_IF_NAME);
    close(fd);
    return INVALID_FD;
}
```
ソースコードを説明すると、

* /dev/tunというtunnel deviceをOPENする
* ioctlで、bt-pan のネットワークインターフェイスを生成する
* ioctlで、bt-panをupする。 /dev/tunを開いたfile descriptorを返す

# データの送信
PANのデータ送信は、PANのネットワークインターフェイス bt-panを経由して行われる。

Bluetoothプロトコルスタックは、bt-panに書き込まれたデータは/dev/tunを経由して読みだす。


## bt-panからデータを受け取るまで

Bluetoothプロトコルスタックは/dev/tunを読み出すために、専用のthreadを使う。

```c
void bta_pan_co_open(uint16_t handle, uint8_t app_id, tBTA_PAN_ROLE local_role,
                            tBTA_PAN_ROLE peer_role, BD_ADDR peer_addr)
{
    BTIF_TRACE_API("bta_pan_co_open:app_id:%d, local_role:%d, peer_role:%d, "
                    "handle:%d", app_id, local_role, peer_role, handle);
    btpan_conn_t* conn = btpan_find_conn_addr(peer_addr);
    if(conn == NULL)
        conn = btpan_new_conn(handle, peer_addr, local_role, peer_role);
    if(conn)
    {
        BTIF_TRACE_DEBUG("bta_pan_co_open:tap_fd:%d, open_count:%d, "
            "conn->handle:%d should = handle:%d, local_role:%d, remote_role:%d",
             btpan_cb.tap_fd, btpan_cb.open_count, conn->handle, handle,
             conn->local_role, conn->remote_role);
        //refresh the role & bt address

        btpan_cb.open_count++;
        conn->handle = handle;
        //bdcpy(conn->peer, peer_addr);
        if(btpan_cb.tap_fd < 0)
        {
            btpan_cb.tap_fd = btpan_tap_open();
            if(btpan_cb.tap_fd >= 0)
                create_tap_read_thread(btpan_cb.tap_fd);
        }
         if(btpan_cb.tap_fd >= 0)
         {
             btpan_cb.flow = 1;
             conn->state = PAN_STATE_OPEN;
             bta_pan_ci_rx_ready(ha*(ndle);
         }
     }
}

```

```
void create_tap_read_thread(int tap_fd) 
{ 
    if (pan_pth < 0) 
        pan_pth = btsock_thread_create(btpan_tap_fd_signaled, NULL); 
    if (pan_pth >= 0) 
        btsock_thread_add_fd(pan_pth, tap_fd, 0, SOCK_THREAD_FD_RD, 0); 
} 

```

```
static void btpan_tap_fd_signaled(int fd, int type, int flags, uint32_t user_id) { 
    assert(btpan_cb.tap_fd == INVALID_FD || btpan_cb.tap_fd == fd); 
 
    if (btpan_cb.tap_fd != fd) { 
        BTIF_TRACE_WARNING("%s Signaled on mismatched fds exp:%d act:%d\n", 
                __func__, btpan_cb.tap_fd, fd); 
        return; 
    } 
 
    if (flags & SOCK_THREAD_FD_EXCEPTION) { 
        btpan_cb.tap_fd = INVALID_FD; 
        btpan_tap_close(fd); 
        btif_pan_close_all_conns(); 
    } else if (flags & SOCK_THREAD_FD_RD) 
        bta_dmexecutecallback(btu_exec_tap_fd_read, INT_TO_PTR(fd)); 
}
```

ソースコードを説明すると

* 先ほど説明したbtpan_tap_open()でbt-panの生成と/dev/tunのopenを行う
* create_tap_read_thread()でスレッドを生成する。
* スレッドはbtpan_tap_fd_signaled()でsignal処理をし、/dev/tunのfdと関連づけられる
* スレッドはSOCK_THREAD_FD_RDのシグナルを受信すると、PANの送信データをbta_dmexecutecallback()に渡す

## PANの送信

```
        bta_dmexecutecallback(btu_exec_tap_fd_read, INT_TO_PTR(fd)); 
```

の先の話です。btaのコールバックとしてbtu_exec_tap_fd_read()を実行します。
 
* buffer を確保する。
* read()でbufferに送信データをコピーする
* 送信データをforward_bnep()に渡す
* forward_bnep()はPAN_WriteBuf()に送信データを渡す。
* PAN_WriteBuf()はBNEP_Write()に送信データを渡す。

# Bluetooth PANの Java部分

frameworks/base に PANのコードが含まれている

frameworks/base/core/java/android/bluetooth/BluetoothPan.java

# Bluetooth tethering

Bluetooth テザリングのコードはframeworks/base に含まれている。

frameworks/base/services/core/java/com/android/server/connectivity/Tethering.java

テザリングを有効にしている部分。TetherInterfaceSMはテザリングのステートマシンのクラス。
```
            TetherInterfaceSM sm = mIfaces.get(iface);
            if (sm != null) {
                if (VDBG) Log.d(TAG, "active iface (" + iface + ") reported as added, ignoring");
                return;
            }
            sm = new TetherInterfaceSM(iface, mLooper, usb);
            mIfaces.put(iface, sm);
            sm.start();
```