贴一张bluez架构图方便理解

user space

APP:上层应⽤程序
Pluseaudio/pipewire:A2DP的组件
Bluetoothd: 蓝⽛守护进程
Bluez: 包括Bluez tool跟Bluez lib

kernel space

内核代码包含以下⼏部分
driver/bluetooth
net/bluetooth
include/net/bluetooth

bluez——mgmt分析

1,cmd下发

linux系统的bluez的代码是存在与两部分,一部分在kernel,实现协议的一些基本功能,还有一部分在user space实现协议的一些上层功能。
两部分之间的交互通过sockt机制,就是mgmt。
cmd的下发主要调用的是mgmt.c中的mgmt_send()函数

unsigned int mgmt_send(struct mgmt *mgmt, uint16_t opcode, uint16_t index,uint16_t length, const void *param,mgmt_request_func_t callback,void *user_data, mgmt_destroy_func_t destroy){return mgmt_send_timeout(mgmt, opcode, index, length, param, callback,user_data, destroy, 0);}

这个函数有8个参数,第一个是mgmt的参数,暂时没找到其定义,第二是比较重要的数值,在mgmt_api和mgmt.h中都有定义和说明,每一个opcode对应一个cmd,在kernel部分也一模一样定义了对应的opcode。
mgmt_send后就是靠opcode是数值对应在kernel中需要调用的对应函数。
第二参数是index
第三个需要传递的参数大小
第四个是需要传递的参数
第五个是传递的回调,用于执行完该cmd后需要回调的数据
第六个是user需要传递的参数,一般未NULL,第六个也是,是预留设计。

2,event上报

除了前面说的cmd下发注册的回调外,kernel部分的event上报一般调用mgmt.c中的mgmt_event()函数来完成,该函数实际是调用的mgmt_send_event()

static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,struct sock *skip_sk){return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len, HCI_SOCK_TRUSTED, skip_sk);}

第一个参数无容置疑就是注册的evnet数值,

bluez inquiry 流程

接下来我们通过bluetoothctl工具来分析bluez 的inquiry流程

bluez源码结构

src:核心程序bluetoothd的源码位置。 其中还包括了shared文件夹,该文件夹编译生成了一个共享库,供bluetoothd和其他程序使用(shared库是重点)。

client:bluetoothctl程序的源码位置。

mesh:mesh协议栈的源码位置,但是不包含proxy相关的功能。

tools:hciattach,hciconfig,hcitool等工具的源码目录,如果打开–enable-testing,–enable-test的话,在该目录中,还会有相关的*-tester执行程序。

monitor:btmon工具的源码位置,到目前5.66为止,这个工具已经很强大了,监控生成的hci数据,可以转化为支持ellisys软件打开的.pkt格式,也可以转化为支持wireshare软件打开的格式.cfa格式。

test:测试蓝牙功能的py脚本,通过dbus接口和bluetoothd进行通信。 dbus提供支持python和c语言的接口。

emulator:从字面意思可以推测出它是用来仿真的,通过阅读代码发现它是仿真controller的,通过btdev_create函数来创建一个虚拟的蓝牙controller设备。 kernel也是支持的,”/dev/vhci”这个设备被虚拟为一个虚拟的蓝牙设备。

lib:bluez的一些基础访问库的源码位置,shared库也引用了lib里面的函数定义。 编译生成libbluetooth-internal.la和libbluetooth.la。

gdbus:dbus的源码仓库。(把dbus封装了一下,方便使用)

ell:The Embedded Learning Library,对嵌入式系统的支持,需要在configure时指定使用ell库,方便编译出更少内存和flash的嵌入式平台的bluez的相关固件。

android:早期的android系统使用的是bluez的开源库,后面改为使用bludroid协议栈了。

peripheral:一个ble外围设备的demo,没有通过dbus和bluetoothd进行通信,而是自己实现了一套,使用了shared库的api。 默认不会编译,需要在configure的时候,–enable-test –enable-testing才会编译该目录的源码。

profiles:android平台的协议栈支持的一部分,配合和android目录一起使用。

plugins:貌似是为bluetoothd程序提供一些插件功能。

obexd:经典蓝牙的obex文件传输协议的源码实现。

unit:一些测试shared库的单元测试case,c代码辨析的。

attrib:gatttool工具的实现源码位置。

btio:bt_io_*的相关函数源码位置,bluetooth的io操作的基础库。

inquiry入口

bluetoothctl程序里面打开蓝牙后,输入scan on即可开始扫描。

在cmd_scan里面就会去判断是打开scan还是关闭scan

static void cmd_scan(int argc, char *argv[]){dbus_bool_t enable;const char *method;const char *mode;if (!parse_argument(argc, argv, scan_arguments, "Mode", &enable,&mode))return bt_shell_noninteractive_quit(EXIT_FAILURE);if (check_default_ctrl() == FALSE)return bt_shell_noninteractive_quit(EXIT_FAILURE);if (enable == TRUE) {if (!g_strcmp0(mode, "")) {g_free(filter.transport);filter.transport = NULL;filter.set = false;} else {g_free(filter.transport);filter.transport = g_strdup(mode);filter.set = false;}set_discovery_filter(false);method = "StartDiscovery";//这里就是dbus总线需要的信息} elsemethod = "StopDiscovery";if (g_dbus_proxy_method_call(default_ctrl->proxy, method,NULL, start_discovery_reply,GUINT_TO_POINTER(enable), NULL) == FALSE) { //进入gdbus目录的client.c执行g_dbus_proxy_method_callbt_shell_printf("Failed to %s discovery\n",enable == TRUE " />"start" : "stop");return bt_shell_noninteractive_quit(EXIT_FAILURE);}}

这个g_dbus_proxy_method_call方法实际上是进行dbus通信,调用method对应的方法,这里就是StartDiscovery。

gboolean g_dbus_proxy_method_call(GDBusProxy *proxy, const char *method,GDBusSetupFunction setup,GDBusReturnFunction function, void *user_data,GDBusDestroyFunction destroy){struct method_call_data *data;GDBusClient *client;DBusMessage *msg;DBusPendingCall *call;if (proxy == NULL || method == NULL)return FALSE;client = proxy->client;if (client == NULL)return FALSE;msg = dbus_message_new_method_call(client->service_name,proxy->obj_path, proxy->interface, method); //"org.bluez","/org/bluez/hci0","org.bluez.Adapter1","StartDiscovery" 这里差不多就是这样if (msg == NULL)return FALSE;if (setup) {DBusMessageIter iter;dbus_message_iter_init_append(msg, &iter);setup(&iter, user_data);}if (!function)return g_dbus_send_message(client->dbus_conn, msg);data = g_try_new0(struct method_call_data, 1);if (data == NULL)return FALSE;data->function = function;data->user_data = user_data;data->destroy = destroy;if (g_dbus_send_message_with_reply(client->dbus_conn, msg,&call, METHOD_CALL_TIMEOUT) == FALSE) {dbus_message_unref(msg);g_free(data);return FALSE;}dbus_pending_call_set_notify(call, method_call_reply, data, g_free);dbus_pending_call_unref(call);dbus_message_unref(msg);return TRUE;}

通过发送的dbus消息,可以知道下一步会进入到src/adapter.c里面去,能看到在src/adapter.c

static const GDBusMethodTable adapter_methods[] = {{ GDBUS_ASYNC_METHOD("StartDiscovery", NULL, NULL, start_discovery) },{ GDBUS_METHOD("SetDiscoveryFilter",GDBUS_ARGS({ "properties", "a{sv}" }), NULL,set_discovery_filter) },{ GDBUS_ASYNC_METHOD("StopDiscovery", NULL, NULL, stop_discovery) },{ GDBUS_ASYNC_METHOD("RemoveDevice",GDBUS_ARGS({ "device", "o" }), NULL, remove_device) },{ GDBUS_METHOD("GetDiscoveryFilters", NULL,GDBUS_ARGS({ "filters", "as" }),get_discovery_filters) },{ GDBUS_EXPERIMENTAL_ASYNC_METHOD("ConnectDevice",GDBUS_ARGS({ "properties", "a{sv}" }), NULL,connect_device) },{ }};//这段代码就可以看到StartDiscovery对应start_discovery-->static DBusMessage *start_discovery(DBusConnection *conn,DBusMessage *msg, void *user_data){struct btd_adapter *adapter = user_data;const char *sender = dbus_message_get_sender(msg);struct discovery_client *client;bool is_discovering;int err;DBG("sender %s", sender);if (!btd_adapter_get_powered(adapter))return btd_error_not_ready(msg);is_discovering = get_discovery_client(adapter, sender, &client);/* * Every client can only start one discovery, if the client * already started a discovery then return an error. */if (is_discovering)return btd_error_busy(msg);/* * If there was pre-set filter, just reconnect it to discovery_list, * and trigger scan. */if (client) {if (client->msg)return btd_error_busy(msg);adapter->set_filter_list = g_slist_remove( adapter->set_filter_list, client);adapter->discovery_list = g_slist_prepend(adapter->discovery_list, client);goto done;}client = g_new0(struct discovery_client, 1);client->adapter = adapter;client->owner = g_strdup(sender);client->discovery_filter = NULL;client->watch = g_dbus_add_disconnect_watch(dbus_conn, sender,discovery_disconnect, client,NULL);adapter->discovery_list = g_slist_prepend(adapter->discovery_list,client);done:/* * Just trigger the discovery here. In case an already running * discovery in idle phase exists, it will be restarted right * away. */err = update_discovery_filter(adapter); //这里触发发现if (!err)return dbus_message_new_method_return(msg);/* If the discovery has to be started wait it complete to reply */if (err == -EINPROGRESS) {client->msg = dbus_message_ref(msg);adapter->client = client;return NULL;}return btd_error_failed(msg, strerror(-err));}-->static int update_discovery_filter(struct btd_adapter *adapter){struct mgmt_cp_start_service_discovery *sd_cp;DBG("");if (discovery_filter_to_mgmt_cp(adapter, &sd_cp)) {btd_error(adapter->dev_id,"discovery_filter_to_mgmt_cp returned error");return -ENOMEM;}/* Only attempt to overwrite current discoverable setting when not * discoverable. */if (!(adapter->current_settings & MGMT_SETTING_DISCOVERABLE)) {GSList *l;for (l = adapter->discovery_list; l; l = g_slist_next(l)) {struct discovery_client *client = l->data;if (!client->discovery_filter)continue;if (client->discovery_filter->discoverable) {set_discovery_discoverable(adapter, true);break;}}}/* * If filters are equal, then don't update scan, except for when * starting discovery. */if (filters_equal(adapter->current_discovery_filter, sd_cp) &&adapter->discovering != 0) {DBG("filters were equal, deciding to not restart the scan.");g_free(sd_cp);return 0;}g_free(adapter->current_discovery_filter);adapter->current_discovery_filter = sd_cp;trigger_start_discovery(adapter, 0);//进入这个方法return -EINPROGRESS;}-->static void trigger_start_discovery(struct btd_adapter *adapter, guint delay){DBG("");cancel_passive_scanning(adapter);if (adapter->discovery_idle_timeout > 0) {timeout_remove(adapter->discovery_idle_timeout);adapter->discovery_idle_timeout = 0;}/* * If the controller got powered down in between, then ensure * that we do not keep trying to restart discovery. * * This is safe-guard and should actually never trigger. */if (!btd_adapter_get_powered(adapter))return;adapter->discovery_idle_timeout = timeout_add_seconds(delay,start_discovery_timeout, adapter, NULL);//这里会跳转到start_discovery_timeout执行}-->static bool start_discovery_timeout(gpointer user_data){struct btd_adapter *adapter = user_data;struct mgmt_cp_start_service_discovery *sd_cp;uint8_t new_type;DBG("");adapter->discovery_idle_timeout = 0;/* If we're doing filtered discovery, it must be quickly restarted */adapter->no_scan_restart_delay = !!adapter->current_discovery_filter;DBG("adapter->current_discovery_filter == %d",!!adapter->current_discovery_filter);new_type = get_scan_type(adapter);if (adapter->discovery_enable == 0x01) {struct mgmt_cp_stop_discovery cp;/* * If we're asked to start regular discovery, and there is an * already running regular discovery and it has the same type, * then just keep it. */if (!adapter->current_discovery_filter &&!adapter->filtered_discovery &&adapter->discovery_type == new_type) {if (adapter->discovering)return FALSE;adapter->discovering = true;g_dbus_emit_property_changed(dbus_conn, adapter->path,ADAPTER_INTERFACE, "Discovering");return FALSE;}/* * Otherwise the current discovery must be stopped. So * queue up a stop discovery command. * * This can happen if a passive scanning for Low Energy * devices is ongoing, or scan type is changed between * regular and filtered, or filter was updated. */cp.type = adapter->discovery_type;mgmt_send(adapter->mgmt, MGMT_OP_STOP_DISCOVERY,adapter->dev_id, sizeof(cp), &cp,NULL, NULL, NULL);/* Don't even bother to try to quickly start discovery * just after stopping it, it would fail with status * MGMT_BUSY. Instead discovering_callback will take * care of that. */return FALSE;}/* Regular discovery is required */if (!adapter->current_discovery_filter) {struct mgmt_cp_start_discovery cp;cp.type = new_type;mgmt_send(adapter->mgmt, ,adapter->dev_id, sizeof(cp), &cp,start_discovery_complete, adapter,NULL);return FALSE;}/* Filtered discovery is required */sd_cp = adapter->current_discovery_filter;DBG("sending MGMT_OP_START_SERVICE_DISCOVERY %d, %d, %d",sd_cp->rssi, sd_cp->type,btohs(sd_cp->uuid_count));mgmt_send(adapter->mgmt, MGMT_OP_START_SERVICE_DISCOVERY,adapter->dev_id, sizeof(*sd_cp) +btohs(sd_cp->uuid_count) * 16,sd_cp, start_discovery_complete, adapter, NULL);return FALSE;}

上面的函数里面就可以看到mgmt_send了,这个函数会通过io下发命令到内核层

kernel层

mgmt_handlers

–> start_discovery()

​ –> start_discovery_internal()

​ –> generic_cmd_complete()

​ –> mgmt_cmd_complete()

​ –> hci_send_to_channel()

static struct hci_mgmt_chan chan = {.channel= HCI_CHANNEL_CONTROL,.handler_count= ARRAY_SIZE(mgmt_handlers),.handlers= mgmt_handlers,.hdev_init= mgmt_init_hdev,}; //mgmt_handlers这个对应的就是对于上层传递的处理int mgmt_init(void){mgmt_chanreturn hci_mgmt_chan_register(&chan); //注册mgmt_chan}//通过查看mgmt_handlers可以知道会调用到那个方法{ start_discovery, MGMT_START_DISCOVERY_SIZE },{ stop_discovery,MGMT_STOP_DISCOVERY_SIZE },static int start_discovery(struct sock *sk, struct hci_dev *hdev, void *data, u16 len){return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY,data, len);}static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,u16 op, void *data, u16 len){struct mgmt_cp_start_discovery *cp = data;struct mgmt_pending_cmd *cmd;u8 status;int err;BT_DBG("%s", hdev->name);hci_dev_lock(hdev);if (!hdev_is_powered(hdev)) {err = mgmt_cmd_complete(sk, hdev->id, op,MGMT_STATUS_NOT_POWERED,&cp->type, sizeof(cp->type));goto failed;}if (hdev->discovery.state != DISCOVERY_STOPPED ||hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY,&cp->type, sizeof(cp->type));goto failed;}if (!discovery_type_is_valid(hdev, cp->type, &status)) {err = mgmt_cmd_complete(sk, hdev->id, op, status,&cp->type, sizeof(cp->type));goto failed;}/* Clear the discovery filter first to free any previously * allocated memory for the UUID list. */hci_discovery_filter_clear(hdev);hdev->discovery.type = cp->type;hdev->discovery.report_invalid_rssi = false;if (op == MGMT_OP_START_LIMITED_DISCOVERY)hdev->discovery.limited = true;elsehdev->discovery.limited = false;cmd = mgmt_pending_add(sk, op, hdev, data, len); //这里添加到列表if (!cmd) {err = -ENOMEM;goto failed;}cmd->cmd_complete = generic_cmd_complete; //hci_discovery_set_state(hdev, DISCOVERY_STARTING);queue_work(hdev->req_workqueue, &hdev->discov_update);err = 0;failed:hci_dev_unlock(hdev);return err;}static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status){return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, cmd->param, cmd->param_len);}//mgmt_util.cint mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,void *rp, size_t rp_len){struct sk_buff *skb, *mskb;struct mgmt_hdr *hdr;struct mgmt_ev_cmd_complete *ev;int err;BT_DBG("sock %p", sk);skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);if (!skb)return -ENOMEM;hdr = skb_put(skb, sizeof(*hdr));hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);hdr->index = cpu_to_le16(index);hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);ev = skb_put(skb, sizeof(*ev) + rp_len);ev->opcode = cpu_to_le16(cmd);ev->status = status;if (rp)memcpy(ev->data, rp, rp_len);mskb = create_monitor_ctrl_event(hdr->index, hci_sock_get_cookie(sk), MGMT_EV_CMD_COMPLETE, sizeof(*ev) + rp_len, ev);if (mskb)skb->tstamp = mskb->tstamp;else__net_timestamp(skb);err = sock_queue_rcv_skb(sk, skb);if (err < 0)kfree_skb(skb);if (mskb) {hci_send_to_channel(HCI_CHANNEL_MONITOR, mskb,HCI_SOCK_TRUSTED, NULL);kfree_skb(mskb);}return err;}

event事件上报

hci_inquiry_result_evt()

–> mgmt_device_found()

​ –> mgmt_event()

​ –> mgmt_send_event()

​ –> hci_send_to_channel()

​ –> __hci_send_to_channel()

//hci_event.c hci_event_packet()case HCI_EV_INQUIRY_RESULT:hci_inquiry_result_evt(hdev, skb);break;static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb){struct inquiry_data data;struct inquiry_info *info = (void *) (skb->data + 1);int num_rsp = *((__u8 *) skb->data);BT_DBG("%s num_rsp %d", hdev->name, num_rsp);if (!num_rsp || skb->len < num_rsp * sizeof(*info) + 1)return;if (hci_dev_test_flag(hdev, HCI_PERIODIC_INQ))return;hci_dev_lock(hdev);for (; num_rsp; num_rsp--, info++) {u32 flags;bacpy(&data.bdaddr, &info->bdaddr);data.pscan_rep_mode= info->pscan_rep_mode;data.pscan_period_mode= info->pscan_period_mode;data.pscan_mode= info->pscan_mode;memcpy(data.dev_class, info->dev_class, 3);data.clock_offset= info->clock_offset;data.rssi= HCI_RSSI_INVALID;data.ssp_mode= 0x00;flags = hci_inquiry_cache_update(hdev, &data, false);mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,info->dev_class, HCI_RSSI_INVALID,flags, NULL, 0, NULL, 0);}hci_dev_unlock(hdev);}//mgmt.cvoid mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 *dev_class, s8 rssi, u32 flags, u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len){char buf[512];struct mgmt_ev_device_found *ev = (void *)buf;size_t ev_size;/* Don't send events for a non-kernel initiated discovery. With * LE one exception is if we have pend_le_reports > 0 in which * case we're doing passive scanning and want these events. */if (!hci_discovery_active(hdev)) {if (link_type == ACL_LINK)return;if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))return;}if (hdev->discovery.result_filtering) {/* We are using service discovery */if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp, scan_rsp_len))return;}if (hdev->discovery.limited) {/* Check for limited discoverable bit */if (dev_class) {if (!(dev_class[1] & 0x20))return;} else {u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL);if (!flags || !(flags[0] & LE_AD_LIMITED))return;}}/* Make sure that the buffer is big enough. The 5 extra bytes * are for the potential CoD field. */if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))return;memset(buf, 0, sizeof(buf));/* In case of device discovery with BR/EDR devices (pre 1.2), the * RSSI value was reported as 0 when not available. This behavior * is kept when using device discovery. This is required for full * backwards compatibility with the API. * * However when using service discovery, the value 127 will be * returned when the RSSI is not available. */if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&link_type == ACL_LINK)rssi = 0;bacpy(&ev->addr.bdaddr, bdaddr);ev->addr.type = link_to_bdaddr(link_type, addr_type);ev->rssi = rssi;ev->flags = cpu_to_le32(flags);if (eir_len > 0)/* Copy EIR or advertising data into event */memcpy(ev->eir, eir, eir_len);if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV, NULL))eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,dev_class, 3);if (scan_rsp_len > 0)/* Append scan response data to event */memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);ev_size = sizeof(*ev) + eir_len + scan_rsp_len;mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);}static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,struct sock *skip_sk){return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len, HCI_SOCK_TRUSTED, skip_sk);}//mgmt_util.cint mgmt_send_event(u16 event, struct hci_dev *hdev, unsigned short channel,void *data, u16 data_len, int flag, struct sock *skip_sk){struct sk_buff *skb;struct mgmt_hdr *hdr;skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);if (!skb)return -ENOMEM;hdr = skb_put(skb, sizeof(*hdr));hdr->opcode = cpu_to_le16(event);if (hdev)hdr->index = cpu_to_le16(hdev->id);elsehdr->index = cpu_to_le16(MGMT_INDEX_NONE);hdr->len = cpu_to_le16(data_len);if (data)skb_put_data(skb, data, data_len);/* Time stamp */__net_timestamp(skb);hci_send_to_channel(channel, skb, flag, skip_sk);if (channel == HCI_CHANNEL_CONTROL)hci_send_monitor_ctrl_event(hdev, event, data, data_len,skb_get_ktime(skb), flag, skip_sk);kfree_skb(skb);return 0;}--> hci_send_to_channel(channel, skb, flag, skip_sk);void hci_send_to_channel(unsigned short channel, struct sk_buff *skb, int flag, struct sock *skip_sk){read_lock(&hci_sk_list.lock);__hci_send_to_channel(channel, skb, flag, skip_sk);read_unlock(&hci_sk_list.lock);}/* Send frame to sockets with specific channel */static void __hci_send_to_channel(unsigned short channel, struct sk_buff *skb,int flag, struct sock *skip_sk){struct sock *sk;BT_DBG("channel %u len %d", channel, skb->len);sk_for_each(sk, &hci_sk_list.head) {struct sk_buff *nskb;/* Ignore socket without the flag set */if (!hci_sock_test_flag(sk, flag))continue;/* Skip the original socket */if (sk == skip_sk)continue;if (sk->sk_state != BT_BOUND)continue;if (hci_pi(sk)->channel != channel)continue;nskb = skb_clone(skb, GFP_ATOMIC);if (!nskb)continue;if (sock_queue_rcv_skb(sk, nskb))kfree_skb(nskb);}}

user space 处理event事件

can_read_data

–> process_notify()

​ –> device_found_callback()

​ –> btd_adapter_device_found() –>dbus

struct mgmt *mgmt_new(int fd){struct mgmt *mgmt;...if (!io_set_read_handler(mgmt->io, can_read_data, mgmt, NULL)) {queue_destroy(mgmt->notify_list, NULL);queue_destroy(mgmt->pending_list, NULL);queue_destroy(mgmt->reply_queue, NULL);queue_destroy(mgmt->request_queue, NULL);io_destroy(mgmt->io);free(mgmt->buf);free(mgmt);return NULL;}...return mgmt_ref(mgmt);}static bool can_read_data(struct io *io, void *user_data) //这个方法在mgmt_new里面注册{struct mgmt *mgmt = user_data;struct mgmt_hdr *hdr;struct mgmt_ev_cmd_complete *cc;struct mgmt_ev_cmd_status *cs;ssize_t bytes_read;uint16_t opcode, event, index, length;bytes_read = read(mgmt->fd, mgmt->buf, mgmt->len);if (bytes_read < 0)return false;if (bytes_read buf;event = btohs(hdr->opcode);index = btohs(hdr->index);length = btohs(hdr->len);if (bytes_read buf + MGMT_HDR_SIZE;opcode = btohs(cc->opcode);DBG(mgmt, "[0x%04x] command 0x%04x complete: 0x%02x",index, opcode, cc->status);request_complete(mgmt, cc->status, opcode, index, length - 3,mgmt->buf + MGMT_HDR_SIZE + 3);break;case MGMT_EV_CMD_STATUS:cs = mgmt->buf + MGMT_HDR_SIZE;opcode = btohs(cs->opcode);DBG(mgmt, "[0x%04x] command 0x%02x status: 0x%02x",index, opcode, cs->status);request_complete(mgmt, cs->status, opcode, index, 0, NULL);break;default:DBG(mgmt, "[0x%04x] event 0x%04x", index, event);process_notify(mgmt, event, index, length,mgmt->buf + MGMT_HDR_SIZE);break;}mgmt_unref(mgmt);return true;}static void process_notify(struct mgmt *mgmt, uint16_t event, uint16_t index,uint16_t length, const void *param){struct event_index match = { .event = event, .index = index,.length = length, .param = param };mgmt->in_notify = true;queue_foreach(mgmt->notify_list, notify_handler, &match);//通过notify_handler到达对应的方法mgmt->in_notify = false;if (mgmt->need_notify_cleanup) {queue_remove_all(mgmt->notify_list, match_notify_removed,NULL, destroy_notify);mgmt->need_notify_cleanup = false;}}mgmt_register(adapter->mgmt, MGMT_EV_DEVICE_FOUND,adapter->dev_id,device_found_callback,adapter, NULL);//adapter.cstatic void device_found_callback(uint16_t index, uint16_t length,const void *param, void *user_data){const struct mgmt_ev_device_found *ev = param;struct btd_adapter *adapter = user_data;const uint8_t *eir;uint16_t eir_len;uint32_t flags;char addr[18];if (length dev_id,"Too short device found event (%u bytes)", length);return;}eir_len = btohs(ev->eir_len);if (length != sizeof(*ev) + eir_len) {btd_error(adapter->dev_id,"Device found event size mismatch (%u != %zu)",length, sizeof(*ev) + eir_len);return;}if (eir_len == 0)eir = NULL;elseeir = ev->eir;flags = le32_to_cpu(ev->flags);ba2str(&ev->addr.bdaddr, addr);DBG("hci%u addr %s, rssi %d flags 0x%04x eir_len %u",index, addr, ev->rssi, flags, eir_len);btd_adapter_device_found(adapter, &ev->addr.bdaddr,ev->addr.type, ev->rssi, flags,eir, eir_len, false);}// client/mgmt.cstatic void device_found(uint16_t index, uint16_t len, const void *param,void *user_data){const struct mgmt_ev_device_found *ev = param;struct mgmt *mgmt = user_data;uint16_t eir_len;uint32_t flags;if (len flags);eir_len = get_le16(&ev->eir_len);if (len != sizeof(*ev) + eir_len) {error("dev_found: expected %zu bytes, got %u bytes",sizeof(*ev) + eir_len, len);return;}if (discovery) {char addr[18], *name;ba2str(&ev->addr.bdaddr, addr);print("hci%u dev_found: %s type %s rssi %d ""flags 0x%04x ", index, addr,typestr(ev->addr.type), ev->rssi, flags);if (ev->addr.type != BDADDR_BREDR)print("AD flags 0x%02x ",eir_get_flags(ev->eir, eir_len));name = eir_get_name(ev->eir, eir_len);if (name)print("name %s", name);elseprint("eir_len %u", eir_len);free(name);}if (discovery && (flags & MGMT_DEV_FOUND_CONFIRM_NAME)) {struct mgmt_cp_confirm_name cp;memset(&cp, 0, sizeof(cp));memcpy(&cp.addr, &ev->addr, sizeof(cp.addr));if (resolve_names)cp.name_known = 0;elsecp.name_known = 1;mgmt_reply(mgmt, MGMT_OP_CONFIRM_NAME, index, sizeof(cp), &cp,confirm_name_rsp, NULL, NULL);}}