5
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Android の Bluetooth PAN の実装を読む

Last updated at Posted at 2016-09-22

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

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

ネットワークインターフェイスの生成

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

btif/include/btif_pan_internal.h
# define TAP_IF_NAME "bt-pan"
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を使う。

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();
5
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?