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);
}