btmon获取hci数据流程

背景

最近在看蓝牙相关的驱动代码,追到hci接收数据处理函数hci_rx_work()(net/bluetooth/hci_core.c),
瞄到下面一段代码:

...
while ((skb = skb_dequeue(&hdev->rx_q))) {
    /* Send copy to monitor */
    hci_send_to_monitor(hdev, skb);
    ...
}

在hci发送数据的处理函数hci_send_frame()中也有类似的代码片段:

...
	/* Time stamp */
	__net_timestamp(skb);

	/* Send copy to monitor */
	hci_send_to_monitor(hdev, skb);

	if (atomic_read(&hdev->promisc)) {
		/* Send copy to the sockets */
		hci_send_to_sock(hdev, skb);
	}
...

突然有了个联想:这个hci_send_to_monitor()莫不是给上层的btmon准备的?
继续追代码,hci_send_to_monitor()函数具体实现如下:

...
	/* Put header before the data */
	hdr = skb_push(skb_copy, HCI_MON_HDR_SIZE);
	hdr->opcode = opcode;
	hdr->index = cpu_to_le16(hdev->id);
	hdr->len = cpu_to_le16(skb->len);

	hci_send_to_channel(HCI_CHANNEL_MONITOR, skb_copy,
			    HCI_SOCK_TRUSTED, NULL);
...

数据最后是发给HCI_CHANNEL_MONITOR通道的,

带着好奇,去翻了下bluez的源码,在monitor目录,即btmon的代码里,
control_tracing()函数中就打开了HCI_CHANNEL_MONITOR通道:

...
	if (open_channel(HCI_CHANNEL_MONITOR) < 0) {
		if (!hcidump_fallback)
			return -1;
		if (hcidump_tracing() < 0)
			return -1;
		return 0;
	}
...

至此,btmon整个获取hci数据的流程就通了,以接收数据为例:

  • 核内(蓝牙驱动):
    具体的HCI接口(H4,usb,sdio等)驱动获取数据
        ->hci_recv_frame() -- 所有的HCI接口的驱动基本上都会调用这里来,比如H4,usb,sdio都会
            -> hci_rx_work() -- 接收工作队列
                -> hci_send_to_monitor() -- Send frame to monitor socket
                    -> hci_send_to_channel(HCI_CHANNEL_MONITOR, ...)
  • 核外(bluez btmon):
    main()
        -> control_tracing()
            -> open_channel(HCI_CHANNEL_MONITOR) -- 打开 HCI_CHANNEL_MONITOR 通道
                -> open_socket -- 打开socket
                    -> data_callback() -- 数据处理回调