在上面2.1中是hci dev的注冊和up,2.3中有bluez的初始化,這兩者是有一個交集的,那就是說bluez初始化後會監聽hci dev的一些event,主要有HCI_DEV_REG和HCI_DEV_UP兩個比較重要,那本集就是主要分析這兩個event帶來的影響。
從上面的分析中,我們已經知道,這兩個event的處理函數是io_stack_event:
[cpp]
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中我們也沒有分析這個函數,這裡我們分析一下吧,反正這個函數終歸是要走的。
[cpp]
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的初始化
[cpp]
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處理的關鍵前提所在。
[cpp]
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的需要進行的各種操作。
[cpp]
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中有分析:
[cpp]
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這個函數了:
[cpp]
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的初始化了
[cpp]
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;