在上面2.1中是hci dev的注册和up,2.3中有bluez的初始化,这两者是有一个交集的,那就是说bluez初始化后会监听hci dev的一些event,主要有HCI_DEV_REG和HCI_DEV_UP两个比较重要,那本集就是主要分析这两个event带来的影响。
从上面的分析中,我们已经知道,这两个event的处理函数是io_stack_event:
static gboolean io_stack_event(GIOChannel *chan, GIOCondition cond, gpointer data) { unsigned char buf[HCI_MAX_FRAME_SIZE], *ptr; evt_stack_internal *si; evt_si_device *sd; hci_event_hdr *eh; int type, fd; ssize_t len; ptr = buf; fd = g_io_channel_unix_get_fd(chan); //读取event的内容 len = read(fd, buf, sizeof(buf)); if (len < 0) { if (errno == EAGAIN) return TRUE; error("Read from control socket failed: %s (%d)", strerror(errno), errno); return FALSE; } type = *ptr++; if (type != HCI_EVENT_PKT) return TRUE; eh = (hci_event_hdr *) ptr; //判断是否是internal的event if (eh->evt != EVT_STACK_INTERNAL) return TRUE; ptr += HCI_EVENT_HDR_SIZE; si = (evt_stack_internal *) ptr; switch (si->type) { case EVT_SI_DEVICE: sd = (void *) &si->data; //event的处理 device_event(sd->event, sd->dev_id); break; } return TRUE; } static void device_event(int event, int index) { switch (event) { //device register后的操作,详细见2.4.1 case HCI_DEV_REG: info("HCI dev %d registered", index); init_device(index, FALSE); break; //unreg,不做详细分析 case HCI_DEV_UNREG: info("HCI dev %d unregistered", index); stop_hci_dev(index); if (devs[index].registered) btd_manager_unregister_adapter(index); break; //device up的操作,详细分析见2.4.2 case HCI_DEV_UP: info("HCI dev %d up", index); devs[index].up = TRUE; device_devup_setup(index); break; //Down的操作 case HCI_DEV_DOWN: info("HCI dev %d down", index); devs[index].up = FALSE; devs[index].pending_cod = 0; devs[index].cache_enable = TRUE; if (!devs[index].pending) { struct btd_adapter *adapter; adapter = manager_find_adapter_by_id(index); if (adapter) btd_adapter_stop(adapter); init_pending(index); } break; } }
2.4.1 device register后的bluez的操作分析
这个函数是bluez收到底层hci dev registe的消息之后的操作。事实上,因为init_known_adapters的存在,这里可能都没有走到。不过,在上面init_known_adapters中我们也没有分析这个函数,这里我们分析一下吧,反正这个函数终归是要走的。
static struct dev_info *init_device(int index, gboolean already_up) { struct dev_info *dev; struct hci_dev_req dr; int dd; pid_t pid; DBG("hci%d", index); //open hci device //其实就是建一个hci对应的socket,并bind,返回的dd就是socket的句柄 dd = hci_open_dev(index); if (dd < 0) { error("Unable to open hci%d: %s (%d)", index, strerror(errno), errno); return NULL; } //max_dev默认为0,申请对应的空间 if (index > max_dev) { max_dev = index; devs = g_realloc(devs, sizeof(devs[0]) * (max_dev + 1)); } //初始化devcie的info,见2.4.1.1 dev = init_dev_info(index, dd, FALSE, already_up); //设置device的pending位,把dev->pending的bdaddr,version,features和name都置位 init_pending(index); //开始hci device,这里会对一系列的event进行监听,具体见2.4.1.2 start_hci_dev(index); //已经up了,就不需要做什么了 /* Avoid forking if nothing else has to be done */ if (already_up) return dev; /* Do initialization in the separate process */ //fork一个进程出来继续,子进程继续下去,父进程这里直接返回device pid = fork(); switch (pid) { case 0: //注册一个子进程退出时调用的函数 atexit(at_child_exit); break; //fork出错,直接返回device,注意这里没有break case -1: error("Fork failed. Can't init device hci%d: %s (%d)", index, strerror(errno), errno); default: //父进程直接返回device DBG("child %d forked", pid); return dev; } memset(&dr, 0, sizeof(dr)); dr.dev_id = index; //根据配置的link mode来进行设置,默认的link policy(7)是不支持park的,支持sniff,roleswitch和hold /* Set link mode */ dr.dev_opt = main_opts.link_mode; if (ioctl(dd, HCISETLINKMODE, (unsigned long) &dr) < 0) error("Can't set link mode on hci%d: %s (%d)", index, strerror(errno), errno); //这里会再次up,其实之前在bluetoothd启动之前的enable_native中已经up过了,所以这里应该没有什么了 /* Start HCI device */ if (ioctl(dd, HCIDEVUP, index) < 0 && errno != EALREADY) { error("Can't init device hci%d: %s (%d)", index, strerror(errno), errno); goto fail; } hci_close_dev(dd); exit(0); fail: hci_close_dev(dd); exit(1); }
至此,device register在bluez和kernel中的所有操作就都完成了。
2.4.1.1 device info的初始化
static struct dev_info *init_dev_info(int index, int sk, gboolean registered, gboolean already_up) { struct dev_info *dev = &devs[index]; //初始化wie0 memset(dev, 0, sizeof(*dev)); dev->id = index; //id就是0,就是hci0 dev->sk = sk; //和刚刚建立的socket绑定 dev->cache_enable = TRUE; //cache enable置位true dev->registered = registered; //registered为false dev->already_up = already_up; //already up是传入的值,这里理论上应该是false dev->io_capability = 0x03; /* No Input No Output */ //no input no output dev->discov_state = DISCOV_HALTED; //初始化discovery的state为DISCOV_HALTED,这个状态的转变我们在inquiry的时候再详细分析 return dev; }
2.4.1.2 hci device的start
这个函数说白了就是对一系列的event进行监听,这也是我们后期能够对event处理的关键前提所在。
static void start_hci_dev(int index) { struct dev_info *dev = &devs[index]; GIOChannel *chan = dev->io; GIOCondition cond; struct hci_filter flt; if (chan) return; info("Listening for HCI events on hci%d", index); //对下面一系列的event进行处理 /* 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); hci_filter_set_event(EVT_LE_META_EVENT, &flt); if (setsockopt(dev->sk, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) { error("Can't set filter on hci%d: %s (%d)", index, strerror(errno), errno); return; } //处理的函数是io_security_event。所以,后期的一系列event上来之后,我们在这里还需要进行一次处理,其实上文中的up过程中的event,是不需要再走这边的,因为在up的时候bluetoothd还没有启动,这里肯定是还没有注册了 chan = g_io_channel_unix_new(dev->sk); cond = G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR; dev->watch_id = g_io_add_watch_full(chan, G_PRIORITY_LOW, cond, io_security_event, GINT_TO_POINTER(index), NULL); dev->io = chan; dev->pin_length = 0; }
2.4.2 device up后的bluez的操作分析
这个函数device up之后bluez的需要进行的各种操作。
static void device_devup_setup(int index) { struct dev_info *dev = &devs[index]; struct hci_dev_info di; read_stored_link_key_cp cp; DBG("hci%d", index); //得到kernel中的device info,并初始化到di中 if (hci_devinfo(index, &di) < 0) return; //检查是否是bredr或者device_raw被置位 if (ignore_device(&di)) return; //拷贝kernel中的bdaddr和features bacpy(&dev->bdaddr, &di.bdaddr); memcpy(dev->features, di.features, 8); /* Set page timeout */ if ((main_opts.flags & (1 << HCID_SET_PAGETO))) { write_page_timeout_cp cp; cp.timeout = htobs(main_opts.pageto); //这里会发送write page timeout的cmd,所以,我们要修改page timeout,就可以通过修改main_opts.pageto来实现,他是可以通过main.conf修改来得到的 hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_WRITE_PAGE_TIMEOUT, WRITE_PAGE_TIMEOUT_CP_SIZE, &cp); } bacpy(&cp.bdaddr, BDADDR_ANY); cp.read_all = 1; //发送read stored link key的cmd hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_READ_STORED_LINK_KEY, READ_STORED_LINK_KEY_CP_SIZE, &cp); //若是没有pending的内容,就init_adapter了。 //我们从上面的分析中知道,这里是有一个pending version的,所以这里先不急,我们来分析一下上面共3个cmd,他们的response所带来的影响。分别是read local version information和write page timeout以及read stored link key。 if (!dev->pending) init_adapter(index); }
2.4.2.1 read local version information的response的影响。
kernel中这个event的影响我们已经分析,不再累述。我们只分析bluez这里的处理:
他的处理在io_security_event中的command complete中有分析:
case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION): ptr += sizeof(evt_cmd_complete); read_local_version_complete(index, ptr); break;
所以就是read_local_version_complete这个函数了:
static void read_local_version_complete(int index, const read_local_version_rp *rp) { struct dev_info *dev = &devs[index]; if (rp->status) return; //得到device的一些信息 dev->ver.manufacturer = btohs(bt_get_unaligned(&rp->manufacturer)); dev->ver.hci_ver = rp->hci_ver; dev->ver.hci_rev = btohs(bt_get_unaligned(&rp->hci_rev)); dev->ver.lmp_ver = rp->lmp_ver; dev->ver.lmp_subver = btohs(bt_get_unaligned(&rp->lmp_subver)); //若是没有设置pending位,则直接return if (!dev->pending) return; //否则,就把pending version的位清空 hci_clear_bit(PENDING_VERSION, &dev->pending); DBG("Got version for hci%d", index); //没有其他pending了,且up了,就需要init adapter了,所以,我们终归是要走到init_adapter的。所以这个函数的分析见2.3.2.4 if (!dev->pending && dev->up) init_adapter(index); }
2.4.2.2 write page timeout的response的分析
依然是command complete,我们会发现,其实我们什么都没有做。包括kernel中也没有做。
2.4.2.3 read stored link key的response的分析
这个和2.4.2.2是一样的。所以什么都没有做。
2.4.2.4 init_adapter函数的分析
这个函数就是adapter的初始化了
static gboolean init_adapter(int index) { //得到对应device的info struct dev_info *dev = &devs[index]; struct btd_adapter *adapter = NULL; gboolean existing_adapter = dev->registered; uint8_t mode, on_mode; gboolean pairable, discoverable; //从上面我们知道dev->registered是false,所以会走if中的resister,就是还没有注册过,就先register,否则就是find,意味着已经注册过了 if (!dev->registered) { //见下面的2.4.2.4.1 adapter = btd_manager_register_adapter(index); if (adapter) dev->registered = TRUE; } else { adapter = manager_find_adapter(&dev->bdaddr); /* FIXME: manager_find_adapter should return a new ref */ btd_adapter_ref(adapter); } //没有创建成功,就直接return false了 if (adapter == NULL) return FALSE; //设置mode,on_mode以及pairable的值,见2.4.2.4.2 btd_adapter_get_mode(adapter, &mode, &on_mode, &pairable); //这个地方是false,所以不会进这个if if (existing_adapter) mode = on_mode; //不是mode off,所以,不会进 if (mode == MODE_OFF) { hciops_power_off(index); goto done; } //这个就是通过一系列的cmd来启动adapter了,详细见2.4.2.4.3 start_adapter(index); //继续start adapter,详细分析2.4.2.4.4 btd_adapter_start(adapter); //因为我们这里目前的mode是connectable,所以,discoverable是0 discoverable = (mode == MODE_DISCOVERABLE); //write scan enable,然后mode是scan_page就是2 hciops_set_discoverable(index, discoverable); //设置pairable的值 hciops_set_pairable(index, pairable); //这里就是发送inquiry cancel的command if (dev->already_up) hciops_stop_inquiry(index); //以上一共有两个cmd,分别是write scan enable,inquiry cancel。这两个cmd的event的分析见2.4.2.4.5 done: btd_adapter_unref(adapter); return TRUE; }
若您觉得该文章对您有帮助,请在下面用鼠标轻轻按一下“顶”,哈哈~~·