ubuntu bluetooth 配对过程

ubuntu bluetooth 配对过程

发表于2012/6/6 21:57:08  2601人阅读

分类: 蓝牙技术

bluetoothd运行时(main函数启动时),加载plugin(调用plugin_init函数):

gboolean plugin_init(GKeyFile *config)
{
	GSList *list;
	GDir *dir;
	const gchar *file;
	gchar **disabled;
	unsigned int i;

	/* Make a call to BtIO API so its symbols got resolved before the
	 * plugins are loaded. */
	bt_io_error_quark();

	if (config)
		disabled = g_key_file_get_string_list(config, "General",
							"DisablePlugins",
							NULL, NULL);
	else
		disabled = NULL;

	info("Loading builtin plugins");

	//add default plugins, those plugins always need for bluetoothd runing
	//those plugins will add to the global link named plugins
	for (i = 0; __bluetooth_builtin[i]; i++) {
		if (is_disabled(__bluetooth_builtin[i]->name, disabled))
			continue;

		add_plugin(NULL,  __bluetooth_builtin[i]);
	}

	if (strlen(PLUGINDIR) == 0) {
		g_strfreev(disabled);
		goto start;
	}

	info("Loading plugins %s\n", PLUGINDIR);

	dir = g_dir_open(PLUGINDIR, 0, NULL);
	if (!dir) {
		g_strfreev(disabled);
		goto start;
	}

	//add user plugins, those plugins stored in PLUGINDIR path, and the 
	//PLUGINDIR = /usr/local/lib/bluetooth/plugins. The bluetoothd will
	//find all those plugins which name *.so, and open them, get the method
	//named bluetooth_plugin_desc, it will also add those plugins to the
	//plugins links.
	while ((file = g_dir_read_name(dir)) != NULL) {
		struct bluetooth_plugin_desc *desc;
		void *handle;
		gchar *filename;

		if (g_str_has_prefix(file, "lib") == TRUE ||
				g_str_has_suffix(file, ".so") == FALSE)
			continue;

		if (is_disabled(file, disabled))
			continue;

		filename = g_build_filename(PLUGINDIR, file, NULL);

		handle = dlopen(filename, RTLD_NOW);
		if (handle == NULL) {
			error("Can't load plugin %s: %s", filename,
								dlerror());
			g_free(filename);
			continue;
		}

		g_free(filename);

		desc = dlsym(handle, "bluetooth_plugin_desc");
		if (desc == NULL) {
			error("Can't load plugin description: %s", dlerror());
			dlclose(handle);
			continue;
		}

		if (add_plugin(handle, desc) == FALSE)
			dlclose(handle);
	}

	g_dir_close(dir);

	g_strfreev(disabled);

start:
	//init all of the plugins by calling the plugins init function
	for (list = plugins; list; list = list->next) {
		struct bluetooth_plugin *plugin = list->data;

		if (plugin->desc->init() < 0) {
			error("Failed to init %s plugin", plugin->desc->name);
			continue;
		}
		info("plugins active\n");
		plugin->active = TRUE;
	}

	return TRUE;
}
函数中__bluetooth_builtin结构体为存储加载的plugin的入口地址,这些地址是通过连接宏##连接的,其中包含hciops模块的加载。此函数将结构体中的地址加载成plugins链表,然后循环调用每个模块的初始化init函数。对应于hciops模块,调用初始化函数为hciops_init。__bluetooth_builtin结构体和连接宏定义如下:

static struct bluetooth_plugin_desc *__bluetooth_builtin[] = {
  &__bluetooth_builtin_audio,
  &__bluetooth_builtin_input,
  &__bluetooth_builtin_serial,
  &__bluetooth_builtin_network,
  &__bluetooth_builtin_service,
  &__bluetooth_builtin_hciops,
  &__bluetooth_builtin_hal,
  &__bluetooth_builtin_storage,
  NULL
};
#define BLUETOOTH_PLUGIN_DEFINE(name, version, priority, init, exit) \
		struct bluetooth_plugin_desc __bluetooth_builtin_ ## name = { \
			#name, version, priority, init, exit \
		};
hciops模块初始化:
static int hciops_init(void)
{
	info("hciops_init\n");
	return btd_register_adapter_ops(&hci_ops);
}

int btd_register_adapter_ops(struct btd_adapter_ops *btd_adapter_ops)
{
	/* Already registered */
	if (adapter_ops)
		return -EALREADY;

	if (btd_adapter_ops->setup == NULL)
		return -EINVAL;

	adapter_ops = btd_adapter_ops;

	return 0;
}
这个初始化函数将静态hci_ops结构体变量赋值给了全局变量adapter_ops。hci_ops结构定义:

static struct btd_adapter_ops hci_ops = {
	.setup = hciops_setup,
	.cleanup = hciops_cleanup,
	.start = hciops_start,
	.stop = hciops_stop,
	.set_powered = hciops_powered,
	.set_connectable = hciops_connectable,
	.set_discoverable = hciops_discoverable,
	.set_limited_discoverable = hciops_set_limited_discoverable,
	.start_discovery = hciops_start_discovery,
	.stop_discovery = hciops_stop_discovery,
	.resolve_name = hciops_resolve_name,
	.cancel_resolve_name = hciops_cancel_resolve_name,
	.set_name = hciops_set_name,
	.read_name = hciops_read_name,
	.set_class = hciops_set_class,
};
在plugin_init加载完plugins后,调用了adapter_ops_setup函数来启动HCI适配层:

int adapter_ops_setup(void)
{
	if (!adapter_ops)
		return -EINVAL;

	return adapter_ops->setup();
}
这个函数即调用里 hci_ops静态全局变量的setup函数,看hci_ops全局变量的定义,.setup指向hciops_setup函数:

static int hciops_setup(void)
{
	struct sockaddr_hci addr;
	struct hci_filter flt;
	GIOChannel *ctl_io, *child_io;
	int sock, err;

	info("hciops_setup\n");

	if (child_pipe[0] != -1)
		return -EALREADY;

	if (pipe(child_pipe) < 0) {
		err = errno;
		error("pipe(): %s (%d)", strerror(err), err);
		return -err;
	}

	child_io = g_io_channel_unix_new(child_pipe[0]);
	g_io_channel_set_close_on_unref(child_io, TRUE);
	child_io_id = g_io_add_watch(child_io,
				G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
				child_exit, NULL);
	g_io_channel_unref(child_io);

	/* Create and bind HCI socket */
	sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
	if (sock < 0) {
		err = errno;
		error("Can't open HCI socket: %s (%d)", strerror(err),
								err);
		return -err;
	}

	/* Set filter */
	hci_filter_clear(&flt);
	hci_filter_set_ptype(HCI_EVENT_PKT, &flt);
	hci_filter_set_event(EVT_STACK_INTERNAL, &flt);
	if (setsockopt(sock, SOL_HCI, HCI_FILTER, &flt,
							sizeof(flt)) < 0) {
		err = errno;
		error("Can't set filter: %s (%d)", strerror(err), err);
		return -err;
	}

	memset(&addr, 0, sizeof(addr));
	addr.hci_family = AF_BLUETOOTH;
	addr.hci_dev = HCI_DEV_NONE;
	if (bind(sock, (struct sockaddr *) &addr,
							sizeof(addr)) < 0) {
		err = errno;
		error("Can't bind HCI socket: %s (%d)",
							strerror(err), err);
		return -err;
	}

	ctl_io = g_io_channel_unix_new(sock);
	g_io_channel_set_close_on_unref(ctl_io, TRUE);

	ctl_io_id = g_io_add_watch(ctl_io, G_IO_IN, io_stack_event, NULL);

	g_io_channel_unref(ctl_io);

	/* Initialize already connected devices */
	return init_known_adapters(sock);
}
在函数的最后,调用里init_known_adapters启动里已知的hci设备,初始化HCI适配器:

static int init_known_adapters(int ctl)
{
	struct hci_dev_list_req *dl;
	struct hci_dev_req *dr;
	int i, err;

	info("init_known_adapters\n");

	dl = g_try_malloc0(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t));
	if (!dl) {
		err = errno;
		error("Can't allocate devlist buffer: %s (%d)",
							strerror(err), err);
		return -err;
	}

	dl->dev_num = HCI_MAX_DEV;
	dr = dl->dev_req;

	if (ioctl(ctl, HCIGETDEVLIST, (void *) dl) < 0) {
		err = errno;
		error("Can't get device list: %s (%d)",
							strerror(err), err);
		g_free(dl);
		return -err;
	}

	for (i = 0; i < dl->dev_num; i++, dr++) {
		device_event(HCI_DEV_REG, dr->dev_id);

		if (hci_test_bit(HCI_UP, &dr->dev_opt)){
			info("here start the hci device\n");
			<span style="box-sizing: border-box; margin: 0px; padding: 0px; color: rgb(0, 0, 0);">device_event(HCI_DEV_UP, dr->dev_id);</span>
		}
	}

	g_free(dl);
	return 0;
}
这个函数通过ioctl获取系统的hci设备列表,然后用device_event(HCI_DEV_UP..)启动HCI设备。device_event接收HCI_DEV_UP消息,调用HCI设备启动函数:

static void device_event(int event, int index)
{
	switch (event) {
	case HCI_DEV_REG:
		info("HCI dev %d registered", index);
		device_devreg_setup(index);
		break;

	case HCI_DEV_UNREG:
		info("HCI dev %d unregistered", index);
		manager_unregister_adapter(index);
		break;

<span style="box-sizing: border-box; margin: 0px; padding: 0px; color: rgb(0, 0, 0); background-color: rgb(255, 255, 255);">	case HCI_DEV_UP:
		info("HCI dev %d up", index);
		device_devup_setup(index);
		break;</span>

	case HCI_DEV_DOWN:
		info("HCI dev %d down", index);
		manager_stop_adapter(index);
		stop_security_manager(index);
		break;
	}
}

启动HCI DEV设备:

static void device_devup_setup(int index)
{
	configure_device(index);

	<span style="box-sizing: border-box; margin: 0px; padding: 0px; color: rgb(0, 0, 0);">start_security_manager</span>(index);

	/* Return value 1 means ioctl(DEVDOWN) was performed */
	if (manager_start_adapter(index) == 1)
		stop_security_manager(index);
}
开始安全管理:

void start_security_manager(int hdev)
{
	GIOChannel *chan = io_data[hdev].channel;
	struct hci_dev_info *di;
	struct hci_filter flt;
	read_stored_link_key_cp cp;
	int dev;

	if (chan)
		return;

	info("Starting security manager %d", hdev);

	if ((dev = hci_open_dev(hdev)) < 0) {
		error("Can't open device hci%d: %s (%d)",
						hdev, strerror(errno), errno);
		return;
	}

	/* Set filter */
	hci_filter_clear(&flt);
	hci_filter_set_ptype(HCI_EVENT_PKT, &flt);
	hci_filter_set_event(EVT_CMD_STATUS, &flt);
	hci_filter_set_event(EVT_CMD_COMPLETE, &flt);
	hci_filter_set_event(EVT_PIN_CODE_REQ, &flt);
	hci_filter_set_event(EVT_LINK_KEY_REQ, &flt);
	hci_filter_set_event(EVT_LINK_KEY_NOTIFY, &flt);
	hci_filter_set_event(EVT_RETURN_LINK_KEYS, &flt);
	hci_filter_set_event(EVT_IO_CAPABILITY_REQUEST, &flt);
	hci_filter_set_event(EVT_IO_CAPABILITY_RESPONSE, &flt);
	hci_filter_set_event(EVT_USER_CONFIRM_REQUEST, &flt);
	hci_filter_set_event(EVT_USER_PASSKEY_REQUEST, &flt);
	hci_filter_set_event(EVT_REMOTE_OOB_DATA_REQUEST, &flt);
	hci_filter_set_event(EVT_USER_PASSKEY_NOTIFY, &flt);
	hci_filter_set_event(EVT_KEYPRESS_NOTIFY, &flt);
	hci_filter_set_event(EVT_SIMPLE_PAIRING_COMPLETE, &flt);
	hci_filter_set_event(EVT_AUTH_COMPLETE, &flt);
	hci_filter_set_event(EVT_REMOTE_NAME_REQ_COMPLETE, &flt);
	hci_filter_set_event(EVT_READ_REMOTE_VERSION_COMPLETE, &flt);
	hci_filter_set_event(EVT_READ_REMOTE_FEATURES_COMPLETE, &flt);
	hci_filter_set_event(EVT_REMOTE_HOST_FEATURES_NOTIFY, &flt);
	hci_filter_set_event(EVT_INQUIRY_COMPLETE, &flt);
	hci_filter_set_event(EVT_INQUIRY_RESULT, &flt);
	hci_filter_set_event(EVT_INQUIRY_RESULT_WITH_RSSI, &flt);
	hci_filter_set_event(EVT_EXTENDED_INQUIRY_RESULT, &flt);
	hci_filter_set_event(EVT_CONN_REQUEST, &flt);
	hci_filter_set_event(EVT_CONN_COMPLETE, &flt);
	hci_filter_set_event(EVT_DISCONN_COMPLETE, &flt);
	if (setsockopt(dev, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
		error("Can't set filter on hci%d: %s (%d)",
						hdev, strerror(errno), errno);
		close(dev);
		return;
	}

	di = g_new(struct hci_dev_info, 1);
	if (hci_devinfo(hdev, di) < 0) {
		error("Can't get device info: %s (%d)",
							strerror(errno), errno);
		close(dev);
		g_free(di);
		return;
	}

	chan = g_io_channel_unix_new(dev);
	g_io_channel_set_close_on_unref(chan, TRUE);
	io_data[hdev].watch_id = g_io_add_watch_full(chan, G_PRIORITY_LOW,
						G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
						<span style="box-sizing: border-box; margin: 0px; padding: 0px; color: rgb(0, 0, 0);">io_security_event</span>, di, (GDestroyNotify) g_free);//注册消息处理函数
	io_data[hdev].channel = chan;
	io_data[hdev].pin_length = -1;

	if (hci_test_bit(HCI_RAW, &di->flags))
		return;

	bacpy(&cp.bdaddr, BDADDR_ANY);
	cp.read_all = 1;

	hci_send_cmd(dev, OGF_HOST_CTL, OCF_READ_STORED_LINK_KEY,
			READ_STORED_LINK_KEY_CP_SIZE, (void *) &cp);
}

这个函数打开里hci dev设备(实际上就是一个socket),设置处理消息类型,然后创建channel,最后用io_security_event函数侦听远程设备发送过来的消息(socket数据)。接收消息函数:

static gboolean io_security_event(GIOChannel *chan, GIOCondition cond,
								gpointer data)
{
	unsigned char buf[HCI_MAX_EVENT_SIZE], *ptr = buf;
	struct hci_dev_info *di = data;
	int type, dev;
	size_t len;
	hci_event_hdr *eh;
	GIOError err;
	evt_cmd_status *evt;

	if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
		delete_channel(chan);
		return FALSE;
	}

	if ((err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf), &len))) {
		if (err == G_IO_ERROR_AGAIN)
			return TRUE;
		delete_channel(chan);
		return FALSE;
	}

	type = *ptr++;

	if (type != HCI_EVENT_PKT)
		return TRUE;

	eh = (hci_event_hdr *) ptr;
	ptr += HCI_EVENT_HDR_SIZE;

	dev = g_io_channel_unix_get_fd(chan);

	ioctl(dev, HCIGETDEVINFO, (void *) di);

	if (hci_test_bit(HCI_RAW, &di->flags))
		return TRUE;

	hci_cmd_print(eh->evt);

	switch (eh->evt) {
	case EVT_CMD_STATUS://命令状态
		cmd_status(dev, &di->bdaddr, ptr);
		break;

	case EVT_CMD_COMPLETE://命令完成
		cmd_complete(dev, &di->bdaddr, ptr);
		break;

	case EVT_REMOTE_NAME_REQ_COMPLETE://获取远程设备名
		remote_name_information(dev, &di->bdaddr, ptr);
		break;

	case EVT_READ_REMOTE_VERSION_COMPLETE:
		remote_version_information(dev, &di->bdaddr, ptr);
		break;

	case EVT_READ_REMOTE_FEATURES_COMPLETE://读取远程设备属性
		remote_features_information(dev, &di->bdaddr, ptr);
		break;

	case EVT_REMOTE_HOST_FEATURES_NOTIFY:
		remote_features_notify(dev, &di->bdaddr, ptr);
		break;

	case EVT_INQUIRY_COMPLETE:
		evt = (evt_cmd_status *) ptr;
		inquiry_complete(&di->bdaddr, evt->status, FALSE);
		break;

	case EVT_INQUIRY_RESULT:
		inquiry_result(dev, &di->bdaddr, eh->plen, ptr);
		break;

	case EVT_INQUIRY_RESULT_WITH_RSSI:
		inquiry_result_with_rssi(dev, &di->bdaddr, eh->plen, ptr);
		break;

	case EVT_EXTENDED_INQUIRY_RESULT:
		extended_inquiry_result(dev, &di->bdaddr, eh->plen, ptr);
		break;

	case EVT_CONN_COMPLETE://连接完成
		conn_complete(dev, di->dev_id, &di->bdaddr, ptr);
		break;

	case EVT_DISCONN_COMPLETE://断开连接
		disconn_complete(dev, &di->bdaddr, ptr);
		break;

	case EVT_AUTH_COMPLETE:
		auth_complete(dev, &di->bdaddr, ptr);
		break;

	case EVT_SIMPLE_PAIRING_COMPLETE:
		simple_pairing_complete(dev, &di->bdaddr, ptr);
		break;

	case EVT_CONN_REQUEST://配对请求
		conn_request(dev, &di->bdaddr, ptr);
		break;
	}

	/* Check for pending command request */
	check_pending_hci_req(di->dev_id, eh->evt);
	switch (eh->evt) {
	case EVT_PIN_CODE_REQ://PIN码请求
		pin_code_request(dev, &di->bdaddr, (bdaddr_t *) ptr);
		break;

	case EVT_LINK_KEY_REQ:
		link_key_request(dev, &di->bdaddr, (bdaddr_t *) ptr);
		break;

	case EVT_LINK_KEY_NOTIFY://linkkey通知
		link_key_notify(dev, &di->bdaddr, ptr);
		break;

	case EVT_RETURN_LINK_KEYS:
		return_link_keys(dev, &di->bdaddr, ptr);
		break;

	case EVT_IO_CAPABILITY_REQUEST:
		io_capa_request(dev, &di->bdaddr, (bdaddr_t *) ptr);
		break;

	case EVT_IO_CAPABILITY_RESPONSE:
		io_capa_response(dev, &di->bdaddr, ptr);
		break;

	case EVT_USER_CONFIRM_REQUEST:
		user_confirm_request(dev, &di->bdaddr, ptr);
		break;

	case EVT_USER_PASSKEY_REQUEST:
		user_passkey_request(dev, &di->bdaddr, ptr);
		break;

	case EVT_USER_PASSKEY_NOTIFY:
		user_passkey_notify(dev, &di->bdaddr, ptr);
		break;

	case EVT_REMOTE_OOB_DATA_REQUEST:
		remote_oob_data_request(dev, &di->bdaddr, ptr);
		break;
	}

	return TRUE;
}

这个函数接收到远程设备发送过来的socket数据,然后解析出cmd,并执行对应的操作。在这里,用9510和PC配对,PC收到如下消息:

手机端输入PIN码前:

EVT_CONN_REQUEST
EVT_CMD_STATUS
EVT_PIN_CODE_REQ
bluetoothd[2395]: pin_code_request (sba=00:1C:26:FB:26:DC, dba=36:15:00:EF:80:6E)
手机端输入PIN码后:
EVT_CMD_COMPLETE
EVT_LINK_KEY_NOTIFY
bluetoothd[2395]: link_key_notify (sba=00:1C:26:FB:26:DC, dba=36:15:00:EF:80:6E, type=0)
EVT_CONN_COMPLETE
EVT_CMD_STATUS
EVT_READ_REMOTE_FEATURES_COMPLETE
EVT_CMD_STATUS
EVT_REMOTE_NAME_REQ_COMPLETE
EVT_CMD_STATUS
EVT_REMOTE_NAME_REQ_COMPLETE
EVT_CMD_STATUS
EVT_DISCONN_COMPLETE

下面看以下各个CMD是啥意思。


EVT_CONN_REQUEST:

static inline void conn_request(int dev, bdaddr_t *sba, void *ptr)
{
	evt_conn_request *evt = ptr;
	uint32_t class = evt->dev_class[0] | (evt->dev_class[1] << 8)
				| (evt->dev_class[2] << 16);

	hcid_dbus_remote_class(sba, &evt->bdaddr, class);//从本地/var/lib/buetooth/bdaddr/classes文件中读取来配对地址的class值,如果有变化,dbus通知

	write_remote_class(sba, &evt->bdaddr, class);//将class写入/var/lib/buetooth/bdaddr/classes文件
}



EVT_CMD_STATUS:

static inline void cmd_status(int dev, bdaddr_t *sba, void *ptr)
{
	evt_cmd_status *evt = ptr;
	uint16_t opcode = btohs(evt->opcode);

	if (opcode == cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY))
		start_inquiry(sba, evt->status, FALSE);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值