diff --git a/bluez-4.78-cc758c498ed98de11e890e56d4500ca85587bc07.diff b/bluez-4.78-cc758c498ed98de11e890e56d4500ca85587bc07.diff new file mode 100644 index 0000000..afa88d1 --- /dev/null +++ b/bluez-4.78-cc758c498ed98de11e890e56d4500ca85587bc07.diff @@ -0,0 +1,1675 @@ +Index: b/lib/mgmt.h +=================================================================== +--- a/lib/mgmt.h ++++ b/lib/mgmt.h +@@ -30,64 +30,75 @@ struct mgmt_hdr { + uint16_t len; + } __packed; + #define MGMT_HDR_SIZE 4 + + #define MGMT_OP_READ_VERSION 0x0001 +-struct mgmt_read_version_rp { ++struct mgmt_rp_read_version { + uint8_t version; + uint16_t revision; + } __packed; +-#define MGMT_READ_VERSION_RP_SIZE 3 + + #define MGMT_OP_READ_FEATURES 0x0002 +-struct mgmt_read_features_rp { ++struct mgmt_rp_read_features { + uint8_t features[8]; + } __packed; +-#define MGMT_READ_FEATURES_RP_SIZE 8 + + #define MGMT_OP_READ_INDEX_LIST 0x0003 +-struct mgmt_read_index_list_rp { ++struct mgmt_rp_read_index_list { + uint16_t num_controllers; + uint16_t index[0]; + } __packed; +-#define MGMT_READ_INDEX_LIST_RP_SIZE 2 + + #define MGMT_OP_READ_INFO 0x0004 +-struct mgmt_read_info_cp { ++struct mgmt_cp_read_info { + uint16_t index; + } __packed; +-#define MGMT_READ_INFO_CP_SIZE 2 +-struct mgmt_read_info_rp { ++struct mgmt_rp_read_info { + uint8_t status; + uint16_t index; + uint8_t type; + bdaddr_t bdaddr; + uint8_t features[8]; + } __packed; +-#define MGMT_READ_INFO_RP_SIZE 18 + + #define MGMT_OP_READ_STATISTICS 0x0005 + + #define MGMT_OP_READ_MODE 0x0006 +-struct mgmt_read_mode_cp { ++struct mgmt_cp_read_mode { + uint16_t index; + } __packed; +-#define MGMT_READ_MODE_CP_SIZE 2 +-struct mgmt_read_mode_rp { ++struct mgmt_rp_read_mode { + uint8_t status; + uint16_t index; + uint8_t enabled; + uint8_t mode; + } __packed; +-#define MGMT_READ_MODE_RP_SIZE 5 + + #define MGMT_OP_WRITE_MODE 0x0007 + + #define MGMT_EV_CMD_COMPLETE 0x0001 +-struct mgmt_cmd_complete_ev { ++struct mgmt_ev_cmd_complete { + uint16_t opcode; + uint8_t data[0]; + } __packed; +-#define MGMT_CMD_COMPLETE_SIZE 2 + + #define MGMT_EV_CMD_STATUS 0x0002 ++struct mgmt_ev_cmd_status { ++ uint8_t status; ++ uint16_t opcode; ++} __packed; ++ + #define MGMT_EV_CONTROLLER_ERROR 0x0003 ++struct mgmt_ev_controller_error { ++ uint16_t index; ++ uint8_t error_code; ++} __packed; ++ ++#define MGMT_EV_INDEX_ADDED 0x0004 ++struct mgmt_ev_index_added { ++ uint16_t index; ++} __packed; ++ ++#define MGMT_EV_INDEX_REMOVED 0x0005 ++struct mgmt_ev_index_removed { ++ uint16_t index; ++} __packed; +Index: b/plugins/hciops.c +=================================================================== +--- a/plugins/hciops.c ++++ b/plugins/hciops.c +@@ -55,15 +55,26 @@ static int child_pipe[2] = { -1, -1 }; + static guint child_io_id = 0; + static guint ctl_io_id = 0; + + #define SK(index) devs[(index)].sk + #define BDADDR(index) devs[(index)].bdaddr ++#define UP(index) devs[(index)].up ++#define READY(index) devs[(index)].ready ++#define CHANNEL(index) devs[(index)].channel ++#define WATCH_ID(index) devs[(index)].watch_id ++#define PIN_LENGTH(index) devs[(index)].pin_length + + static int max_dev = -1; + static struct dev_info { + int sk; + bdaddr_t bdaddr; ++ gboolean up; ++ gboolean ready; ++ ++ GIOChannel *channel; ++ guint watch_id; ++ int pin_length; + } *devs = NULL; + + static int ignore_device(struct hci_dev_info *di) + { + return hci_test_bit(HCI_RAW, &di->flags) || di->type >> 4 != HCI_BREDR; +@@ -71,10 +82,11 @@ static int ignore_device(struct hci_dev_ + + static void init_dev_info(int index, int sk) + { + memset(&devs[index], 0, sizeof(struct dev_info)); + SK(index) = sk; ++ PIN_LENGTH(index) = -1; + } + + /* Async HCI command handling with callback support */ + + struct hci_cmd_data { +@@ -249,33 +261,23 @@ static int hciops_encrypt_link(int index + + /* End async HCI command handling */ + + /* Start of HCI event callbacks */ + +-struct g_io_info { +- GIOChannel *channel; +- int watch_id; +- int pin_length; +-}; +- +-static struct g_io_info io_data[HCI_MAX_DEV]; +- +-static int get_handle(int dev, bdaddr_t *sba, bdaddr_t *dba, uint16_t *handle) ++static int get_handle(int index, bdaddr_t *dba, uint16_t *handle) + { + struct hci_conn_list_req *cl; + struct hci_conn_info *ci; +- char addr[18]; + int i; + + cl = g_malloc0(10 * sizeof(*ci) + sizeof(*cl)); + +- ba2str(sba, addr); +- cl->dev_id = hci_devid(addr); ++ cl->dev_id = index; + cl->conn_num = 10; + ci = cl->conn_info; + +- if (ioctl(dev, HCIGETCONNLIST, (void *) cl) < 0) { ++ if (ioctl(SK(index), HCIGETCONNLIST, (void *) cl) < 0) { + g_free(cl); + return -EIO; + } + + for (i = 0; i < cl->conn_num; i++, ci++) { +@@ -289,25 +291,23 @@ static int get_handle(int dev, bdaddr_t + g_free(cl); + + return -ENOENT; + } + +-static inline int get_bdaddr(int dev, bdaddr_t *sba, uint16_t handle, bdaddr_t *dba) ++static inline int get_bdaddr(int index, uint16_t handle, bdaddr_t *dba) + { + struct hci_conn_list_req *cl; + struct hci_conn_info *ci; +- char addr[18]; + int i; + + cl = g_malloc0(10 * sizeof(*ci) + sizeof(*cl)); + +- ba2str(sba, addr); +- cl->dev_id = hci_devid(addr); ++ cl->dev_id = index; + cl->conn_num = 10; + ci = cl->conn_info; + +- if (ioctl(dev, HCIGETCONNLIST, (void *) cl) < 0) { ++ if (ioctl(SK(index), HCIGETCONNLIST, (void *) cl) < 0) { + g_free(cl); + return -EIO; + } + + for (i = 0; i < cl->conn_num; i++, ci++) +@@ -344,33 +344,33 @@ static inline void update_lastused(bdadd + write_lastused_info(sba, dba, tm); + } + + /* Link Key handling */ + +-static void link_key_request(int dev, bdaddr_t *sba, bdaddr_t *dba) ++static void link_key_request(int index, bdaddr_t *dba) + { + struct btd_adapter *adapter; + struct btd_device *device; + struct hci_auth_info_req req; + unsigned char key[16]; + char sa[18], da[18]; + uint8_t type; + int err; + +- ba2str(sba, sa); ba2str(dba, da); ++ ba2str(&BDADDR(index), sa); ba2str(dba, da); + info("link_key_request (sba=%s, dba=%s)", sa, da); + +- adapter = manager_find_adapter(sba); ++ adapter = manager_find_adapter(&BDADDR(index)); + if (adapter) + device = adapter_find_device(adapter, da); + else + device = NULL; + + memset(&req, 0, sizeof(req)); + bacpy(&req.bdaddr, dba); + +- err = ioctl(dev, HCIGETAUTHINFO, (unsigned long) &req); ++ err = ioctl(SK(index), HCIGETAUTHINFO, (unsigned long) &req); + if (err < 0) { + if (errno != EINVAL) + DBG("HCIGETAUTHINFO failed %s (%d)", + strerror(errno), errno); + req.type = 0x00; +@@ -378,244 +378,232 @@ static void link_key_request(int dev, bd + + DBG("kernel auth requirements = 0x%02x", req.type); + + if (main_opts.debug_keys && device && device_get_debug_key(device, key)) + type = 0x03; +- else if (read_link_key(sba, dba, key, &type) < 0 || type == 0x03) { ++ else if (read_link_key(&BDADDR(index), dba, key, &type) < 0 || ++ type == 0x03) { + /* Link key not found */ +- hci_send_cmd(dev, OGF_LINK_CTL, OCF_LINK_KEY_NEG_REPLY, 6, dba); ++ hci_send_cmd(SK(index), OGF_LINK_CTL, OCF_LINK_KEY_NEG_REPLY, ++ 6, dba); + return; + } + + /* Link key found */ + + DBG("link key type = 0x%02x", type); + + /* Don't use unauthenticated combination keys if MITM is + * required */ + if (type == 0x04 && req.type != 0xff && (req.type & 0x01)) +- hci_send_cmd(dev, OGF_LINK_CTL, OCF_LINK_KEY_NEG_REPLY, ++ hci_send_cmd(SK(index), OGF_LINK_CTL, OCF_LINK_KEY_NEG_REPLY, + 6, dba); + else { + link_key_reply_cp lr; + + memcpy(lr.link_key, key, 16); + bacpy(&lr.bdaddr, dba); + +- hci_send_cmd(dev, OGF_LINK_CTL, OCF_LINK_KEY_REPLY, ++ hci_send_cmd(SK(index), OGF_LINK_CTL, OCF_LINK_KEY_REPLY, + LINK_KEY_REPLY_CP_SIZE, &lr); + } + } + +-static void link_key_notify(int dev, bdaddr_t *sba, void *ptr) ++static void link_key_notify(int index, void *ptr) + { + evt_link_key_notify *evt = ptr; + bdaddr_t *dba = &evt->bdaddr; + char sa[18], da[18]; +- int dev_id, err; ++ int err; + unsigned char old_key[16]; + uint8_t old_key_type; + +- ba2str(sba, sa); ba2str(dba, da); ++ ba2str(&BDADDR(index), sa); ba2str(dba, da); + info("link_key_notify (sba=%s, dba=%s, type=%d)", sa, da, + evt->key_type); + +- err = read_link_key(sba, dba, old_key, &old_key_type); ++ err = read_link_key(&BDADDR(index), dba, old_key, &old_key_type); + if (err < 0) + old_key_type = 0xff; + +- dev_id = hci_devid(sa); +- if (dev_id < 0) +- err = -errno; +- else { +- err = btd_event_link_key_notify(sba, dba, evt->link_key, +- evt->key_type, +- io_data[dev_id].pin_length, +- old_key_type); +- io_data[dev_id].pin_length = -1; +- } ++ err = btd_event_link_key_notify(&BDADDR(index), dba, evt->link_key, ++ evt->key_type, PIN_LENGTH(index), ++ old_key_type); ++ PIN_LENGTH(index) = -1; + + if (err < 0) { + uint16_t handle; + + if (err == -ENODEV) +- btd_event_bonding_process_complete(sba, dba, ++ btd_event_bonding_process_complete(&BDADDR(index), dba, + HCI_OE_LOW_RESOURCES); + else +- btd_event_bonding_process_complete(sba, dba, ++ btd_event_bonding_process_complete(&BDADDR(index), dba, + HCI_MEMORY_FULL); + +- if (get_handle(dev, sba, dba, &handle) == 0) { ++ if (get_handle(index, dba, &handle) == 0) { + disconnect_cp cp; + + memset(&cp, 0, sizeof(cp)); + cp.handle = htobs(handle); + cp.reason = HCI_OE_LOW_RESOURCES; + +- hci_send_cmd(dev, OGF_LINK_CTL, OCF_DISCONNECT, ++ hci_send_cmd(SK(index), OGF_LINK_CTL, OCF_DISCONNECT, + DISCONNECT_CP_SIZE, &cp); + } + } + } + +-static void return_link_keys(int dev, bdaddr_t *sba, void *ptr) ++static void return_link_keys(int index, void *ptr) + { + evt_return_link_keys *evt = ptr; + uint8_t num = evt->num_keys; + unsigned char key[16]; + char sa[18], da[18]; + bdaddr_t dba; + int i; + +- ba2str(sba, sa); ++ ba2str(&BDADDR(index), sa); + ptr++; + + for (i = 0; i < num; i++) { + bacpy(&dba, ptr); ba2str(&dba, da); + memcpy(key, ptr + 6, 16); + + info("return_link_keys (sba=%s, dba=%s)", sa, da); + +- btd_event_returned_link_key(sba, &dba); ++ btd_event_returned_link_key(&BDADDR(index), &dba); + + ptr += 22; + } + } + + /* Simple Pairing handling */ + +-static void user_confirm_request(int dev, bdaddr_t *sba, void *ptr) ++static void user_confirm_request(int index, void *ptr) + { + evt_user_confirm_request *req = ptr; + +- if (btd_event_user_confirm(sba, &req->bdaddr, ++ if (btd_event_user_confirm(&BDADDR(index), &req->bdaddr, + btohl(req->passkey)) < 0) +- hci_send_cmd(dev, OGF_LINK_CTL, ++ hci_send_cmd(SK(index), OGF_LINK_CTL, + OCF_USER_CONFIRM_NEG_REPLY, 6, ptr); + } + +-static void user_passkey_request(int dev, bdaddr_t *sba, void *ptr) ++static void user_passkey_request(int index, void *ptr) + { + evt_user_passkey_request *req = ptr; + +- if (btd_event_user_passkey(sba, &req->bdaddr) < 0) +- hci_send_cmd(dev, OGF_LINK_CTL, ++ if (btd_event_user_passkey(&BDADDR(index), &req->bdaddr) < 0) ++ hci_send_cmd(SK(index), OGF_LINK_CTL, + OCF_USER_PASSKEY_NEG_REPLY, 6, ptr); + } + +-static void user_passkey_notify(int dev, bdaddr_t *sba, void *ptr) ++static void user_passkey_notify(int index, void *ptr) + { + evt_user_passkey_notify *req = ptr; + +- btd_event_user_notify(sba, &req->bdaddr, btohl(req->passkey)); ++ btd_event_user_notify(&BDADDR(index), &req->bdaddr, ++ btohl(req->passkey)); + } + +-static void remote_oob_data_request(int dev, bdaddr_t *sba, void *ptr) ++static void remote_oob_data_request(int index, void *ptr) + { +- hci_send_cmd(dev, OGF_LINK_CTL, OCF_REMOTE_OOB_DATA_NEG_REPLY, 6, ptr); ++ hci_send_cmd(SK(index), OGF_LINK_CTL, ++ OCF_REMOTE_OOB_DATA_NEG_REPLY, 6, ptr); + } + +-static void io_capa_request(int dev, bdaddr_t *sba, bdaddr_t *dba) ++static void io_capa_request(int index, void *ptr) + { ++ bdaddr_t *dba = ptr; + char sa[18], da[18]; + uint8_t cap, auth; + +- ba2str(sba, sa); ba2str(dba, da); ++ ba2str(&BDADDR(index), sa); ba2str(dba, da); + info("io_capa_request (sba=%s, dba=%s)", sa, da); + +- if (btd_event_get_io_cap(sba, dba, &cap, &auth) < 0) { ++ if (btd_event_get_io_cap(&BDADDR(index), dba, &cap, &auth) < 0) { + io_capability_neg_reply_cp cp; + memset(&cp, 0, sizeof(cp)); + bacpy(&cp.bdaddr, dba); + cp.reason = HCI_PAIRING_NOT_ALLOWED; +- hci_send_cmd(dev, OGF_LINK_CTL, OCF_IO_CAPABILITY_NEG_REPLY, ++ hci_send_cmd(SK(index), OGF_LINK_CTL, ++ OCF_IO_CAPABILITY_NEG_REPLY, + IO_CAPABILITY_NEG_REPLY_CP_SIZE, &cp); + } else { + io_capability_reply_cp cp; + memset(&cp, 0, sizeof(cp)); + bacpy(&cp.bdaddr, dba); + cp.capability = cap; + cp.oob_data = 0x00; + cp.authentication = auth; +- hci_send_cmd(dev, OGF_LINK_CTL, OCF_IO_CAPABILITY_REPLY, ++ hci_send_cmd(SK(index), OGF_LINK_CTL, OCF_IO_CAPABILITY_REPLY, + IO_CAPABILITY_REPLY_CP_SIZE, &cp); + } + } + +-static void io_capa_response(int dev, bdaddr_t *sba, void *ptr) ++static void io_capa_response(int index, void *ptr) + { + evt_io_capability_response *evt = ptr; + char sa[18], da[18]; + +- ba2str(sba, sa); ba2str(&evt->bdaddr, da); ++ ba2str(&BDADDR(index), sa); ba2str(&evt->bdaddr, da); + info("io_capa_response (sba=%s, dba=%s)", sa, da); + +- btd_event_set_io_cap(sba, &evt->bdaddr, ++ btd_event_set_io_cap(&BDADDR(index), &evt->bdaddr, + evt->capability, evt->authentication); + } + + /* PIN code handling */ + +-void set_pin_length(bdaddr_t *sba, int length) +-{ +- char addr[18]; +- int dev_id; +- +- ba2str(sba, addr); +- dev_id = hci_devid(addr); +- +- if (dev_id >= 0) +- io_data[dev_id].pin_length = length; +-} +- +-static void pin_code_request(int dev, bdaddr_t *sba, bdaddr_t *dba) ++static void pin_code_request(int index, bdaddr_t *dba) + { + pin_code_reply_cp pr; + struct hci_conn_info_req *cr; + struct hci_conn_info *ci; + char sa[18], da[18], pin[17]; + int pinlen; + + memset(&pr, 0, sizeof(pr)); + bacpy(&pr.bdaddr, dba); + +- ba2str(sba, sa); ba2str(dba, da); ++ ba2str(&BDADDR(index), sa); ba2str(dba, da); + info("pin_code_request (sba=%s, dba=%s)", sa, da); + + cr = g_malloc0(sizeof(*cr) + sizeof(*ci)); + + bacpy(&cr->bdaddr, dba); + cr->type = ACL_LINK; +- if (ioctl(dev, HCIGETCONNINFO, (unsigned long) cr) < 0) { ++ if (ioctl(SK(index), HCIGETCONNINFO, (unsigned long) cr) < 0) { + error("Can't get conn info: %s (%d)", strerror(errno), errno); + goto reject; + } + ci = cr->conn_info; + + memset(pin, 0, sizeof(pin)); +- pinlen = read_pin_code(sba, dba, pin); ++ pinlen = read_pin_code(&BDADDR(index), dba, pin); + + if (pinlen > 0) { +- set_pin_length(sba, pinlen); ++ PIN_LENGTH(index) = pinlen; + memcpy(pr.pin_code, pin, pinlen); + pr.pin_len = pinlen; +- hci_send_cmd(dev, OGF_LINK_CTL, OCF_PIN_CODE_REPLY, +- PIN_CODE_REPLY_CP_SIZE, &pr); ++ hci_send_cmd(SK(index), OGF_LINK_CTL, OCF_PIN_CODE_REPLY, ++ PIN_CODE_REPLY_CP_SIZE, &pr); + } else { + /* Request PIN from passkey agent */ +- if (btd_event_request_pin(dev, sba, ci) < 0) ++ if (btd_event_request_pin(&BDADDR(index), ci) < 0) + goto reject; + } + + g_free(cr); + + return; + + reject: + g_free(cr); + +- hci_send_cmd(dev, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, 6, dba); ++ hci_send_cmd(SK(index), OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, 6, dba); + } + + static void start_inquiry(bdaddr_t *local, uint8_t status, gboolean periodic) + { + struct btd_adapter *adapter; +@@ -663,20 +651,22 @@ static void inquiry_complete(bdaddr_t *l + state = adapter_get_state(adapter); + state &= ~(STATE_STDINQ | STATE_PINQ); + adapter_set_state(adapter, state); + } + +-static inline void remote_features_notify(int dev, bdaddr_t *sba, void *ptr) ++static inline void remote_features_notify(int index, void *ptr) + { + evt_remote_host_features_notify *evt = ptr; + + if (evt->features[0] & 0x01) +- btd_event_set_legacy_pairing(sba, &evt->bdaddr, FALSE); ++ btd_event_set_legacy_pairing(&BDADDR(index), &evt->bdaddr, ++ FALSE); + else +- btd_event_set_legacy_pairing(sba, &evt->bdaddr, TRUE); ++ btd_event_set_legacy_pairing(&BDADDR(index), &evt->bdaddr, ++ TRUE); + +- write_features_info(sba, &evt->bdaddr, NULL, evt->features); ++ write_features_info(&BDADDR(index), &evt->bdaddr, NULL, evt->features); + } + + static void write_le_host_complete(bdaddr_t *sba, uint8_t status) + { + struct btd_adapter *adapter; +@@ -712,140 +702,163 @@ static void read_local_ext_features_comp + return; + + btd_adapter_update_local_ext_features(adapter, rp->features); + } + +-static inline void cmd_status(int dev, bdaddr_t *sba, void *ptr) ++static void read_bd_addr_complete(int index, read_bd_addr_rp *rp) ++{ ++ if (rp->status) ++ return; ++ ++ bacpy(&BDADDR(index), &rp->bdaddr); ++ ++ if (READY(index)) ++ return; ++ ++ READY(index) = TRUE; ++ ++ info("Got bdaddr for hci%d", index); ++ ++ if (UP(index)) ++ manager_start_adapter(index); ++} ++ ++static inline void cmd_status(int index, 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); ++ start_inquiry(&BDADDR(index), evt->status, FALSE); + } + +-static void read_scan_complete(bdaddr_t *sba, uint8_t status, void *ptr) ++static void read_scan_complete(int index, uint8_t status, void *ptr) + { + struct btd_adapter *adapter; + read_scan_enable_rp *rp = ptr; + +- adapter = manager_find_adapter(sba); ++ adapter = manager_find_adapter(&BDADDR(index)); + + if (!adapter) { + error("Unable to find matching adapter"); + return; + } + + adapter_mode_changed(adapter, rp->enable); + } + +-static inline void cmd_complete(int dev, bdaddr_t *sba, void *ptr) ++static inline void cmd_complete(int index, void *ptr) + { + evt_cmd_complete *evt = ptr; + uint16_t opcode = btohs(evt->opcode); + uint8_t status = *((uint8_t *) ptr + EVT_CMD_COMPLETE_SIZE); + + switch (opcode) { + case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_EXT_FEATURES): + ptr += sizeof(evt_cmd_complete); +- read_local_ext_features_complete(sba, ptr); ++ read_local_ext_features_complete(&BDADDR(index), ptr); ++ break; ++ case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_BD_ADDR): ++ ptr += sizeof(evt_cmd_complete); ++ read_bd_addr_complete(index, ptr); + break; + case cmd_opcode_pack(OGF_LINK_CTL, OCF_PERIODIC_INQUIRY): +- start_inquiry(sba, status, TRUE); ++ start_inquiry(&BDADDR(index), status, TRUE); + break; + case cmd_opcode_pack(OGF_LINK_CTL, OCF_EXIT_PERIODIC_INQUIRY): +- inquiry_complete(sba, status, TRUE); ++ inquiry_complete(&BDADDR(index), status, TRUE); + break; + case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY_CANCEL): +- inquiry_complete(sba, status, FALSE); ++ inquiry_complete(&BDADDR(index), status, FALSE); + break; + case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_LE_HOST_SUPPORTED): +- write_le_host_complete(sba, status); ++ write_le_host_complete(&BDADDR(index), status); + break; + case cmd_opcode_pack(OGF_LE_CTL, OCF_LE_SET_SCAN_ENABLE): +- btd_event_le_set_scan_enable_complete(sba, status); ++ btd_event_le_set_scan_enable_complete(&BDADDR(index), status); + break; + case cmd_opcode_pack(OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME): +- adapter_setname_complete(sba, status); ++ adapter_setname_complete(&BDADDR(index), status); + break; + case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE): +- btd_event_setscan_enable_complete(sba); ++ btd_event_setscan_enable_complete(&BDADDR(index)); + break; + case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_SCAN_ENABLE): + ptr += sizeof(evt_cmd_complete); +- read_scan_complete(sba, status, ptr); ++ read_scan_complete(index, status, ptr); + break; + case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV): +- adapter_set_class_complete(sba, status); ++ adapter_set_class_complete(&BDADDR(index), status); + break; + case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SIMPLE_PAIRING_MODE): +- btd_event_write_simple_pairing_mode_complete(sba); ++ btd_event_write_simple_pairing_mode_complete(&BDADDR(index)); + break; + case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_SIMPLE_PAIRING_MODE): + ptr += sizeof(evt_cmd_complete); +- btd_event_read_simple_pairing_mode_complete(sba, ptr); ++ btd_event_read_simple_pairing_mode_complete(&BDADDR(index), ++ ptr); + break; + case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_LOCAL_NAME): + ptr += sizeof(evt_cmd_complete); +- adapter_update_local_name(sba, status, ptr); ++ adapter_update_local_name(&BDADDR(index), status, ptr); + break; + case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_INQ_RESPONSE_TX_POWER_LEVEL): + ptr += sizeof(evt_cmd_complete); +- adapter_update_tx_power(sba, status, ptr); ++ adapter_update_tx_power(&BDADDR(index), status, ptr); + break; + }; + } + +-static inline void remote_name_information(int dev, bdaddr_t *sba, void *ptr) ++static inline void remote_name_information(int index, void *ptr) + { + evt_remote_name_req_complete *evt = ptr; + char name[MAX_NAME_LENGTH + 1]; + + memset(name, 0, sizeof(name)); + + if (!evt->status) + memcpy(name, evt->name, MAX_NAME_LENGTH); + +- btd_event_remote_name(sba, &evt->bdaddr, evt->status, name); ++ btd_event_remote_name(&BDADDR(index), &evt->bdaddr, evt->status, name); + } + +-static inline void remote_version_information(int dev, bdaddr_t *sba, void *ptr) ++static inline void remote_version_information(int index, void *ptr) + { + evt_read_remote_version_complete *evt = ptr; + bdaddr_t dba; + + if (evt->status) + return; + +- if (get_bdaddr(dev, sba, btohs(evt->handle), &dba) < 0) ++ if (get_bdaddr(index, btohs(evt->handle), &dba) < 0) + return; + +- write_version_info(sba, &dba, btohs(evt->manufacturer), ++ write_version_info(&BDADDR(index), &dba, btohs(evt->manufacturer), + evt->lmp_ver, btohs(evt->lmp_subver)); + } + +-static inline void inquiry_result(int dev, bdaddr_t *sba, int plen, void *ptr) ++static inline void inquiry_result(int index, int plen, void *ptr) + { + uint8_t num = *(uint8_t *) ptr++; + int i; + + for (i = 0; i < num; i++) { + inquiry_info *info = ptr; +- uint32_t class = info->dev_class[0] +- | (info->dev_class[1] << 8) +- | (info->dev_class[2] << 16); ++ uint32_t class = info->dev_class[0] | ++ (info->dev_class[1] << 8) | ++ (info->dev_class[2] << 16); + +- btd_event_inquiry_result(sba, &info->bdaddr, class, 0, NULL); ++ btd_event_inquiry_result(&BDADDR(index), &info->bdaddr, class, ++ 0, NULL); + +- update_lastseen(sba, &info->bdaddr); ++ update_lastseen(&BDADDR(index), &info->bdaddr); + + ptr += INQUIRY_INFO_SIZE; + } + } + +-static inline void inquiry_result_with_rssi(int dev, bdaddr_t *sba, +- int plen, void *ptr) ++static inline void inquiry_result_with_rssi(int index, int plen, void *ptr) + { + uint8_t num = *(uint8_t *) ptr++; + int i; + + if (!num) +@@ -853,99 +866,97 @@ static inline void inquiry_result_with_r + + if ((plen - 1) / num == INQUIRY_INFO_WITH_RSSI_AND_PSCAN_MODE_SIZE) { + for (i = 0; i < num; i++) { + inquiry_info_with_rssi_and_pscan_mode *info = ptr; + uint32_t class = info->dev_class[0] +- | (info->dev_class[1] << 8) +- | (info->dev_class[2] << 16); ++ | (info->dev_class[1] << 8) ++ | (info->dev_class[2] << 16); + +- btd_event_inquiry_result(sba, &info->bdaddr, ++ btd_event_inquiry_result(&BDADDR(index), &info->bdaddr, + class, info->rssi, NULL); + +- update_lastseen(sba, &info->bdaddr); ++ update_lastseen(&BDADDR(index), &info->bdaddr); + + ptr += INQUIRY_INFO_WITH_RSSI_AND_PSCAN_MODE_SIZE; + } + } else { + for (i = 0; i < num; i++) { + inquiry_info_with_rssi *info = ptr; + uint32_t class = info->dev_class[0] +- | (info->dev_class[1] << 8) +- | (info->dev_class[2] << 16); ++ | (info->dev_class[1] << 8) ++ | (info->dev_class[2] << 16); + +- btd_event_inquiry_result(sba, &info->bdaddr, ++ btd_event_inquiry_result(&BDADDR(index), &info->bdaddr, + class, info->rssi, NULL); + +- update_lastseen(sba, &info->bdaddr); ++ update_lastseen(&BDADDR(index), &info->bdaddr); + + ptr += INQUIRY_INFO_WITH_RSSI_SIZE; + } + } + } + +-static inline void extended_inquiry_result(int dev, bdaddr_t *sba, +- int plen, void *ptr) ++static inline void extended_inquiry_result(int index, int plen, void *ptr) + { + uint8_t num = *(uint8_t *) ptr++; + int i; + + for (i = 0; i < num; i++) { + extended_inquiry_info *info = ptr; + uint32_t class = info->dev_class[0] +- | (info->dev_class[1] << 8) +- | (info->dev_class[2] << 16); ++ | (info->dev_class[1] << 8) ++ | (info->dev_class[2] << 16); + +- btd_event_inquiry_result(sba, &info->bdaddr, class, ++ btd_event_inquiry_result(&BDADDR(index), &info->bdaddr, class, + info->rssi, info->data); + +- update_lastseen(sba, &info->bdaddr); ++ update_lastseen(&BDADDR(index), &info->bdaddr); + + ptr += EXTENDED_INQUIRY_INFO_SIZE; + } + } + +-static inline void remote_features_information(int dev, bdaddr_t *sba, +- void *ptr) ++static inline void remote_features_information(int index, void *ptr) + { + evt_read_remote_features_complete *evt = ptr; + bdaddr_t dba; + + if (evt->status) + return; + +- if (get_bdaddr(dev, sba, btohs(evt->handle), &dba) < 0) ++ if (get_bdaddr(index, btohs(evt->handle), &dba) < 0) + return; + +- write_features_info(sba, &dba, evt->features, NULL); ++ write_features_info(&BDADDR(index), &dba, evt->features, NULL); + } + +-static inline void conn_complete(int dev, int dev_id, bdaddr_t *sba, void *ptr) ++static inline void conn_complete(int index, void *ptr) + { + evt_conn_complete *evt = ptr; + char filename[PATH_MAX]; + char local_addr[18], peer_addr[18], *str; + struct btd_adapter *adapter; + +- adapter = manager_find_adapter(sba); ++ adapter = manager_find_adapter(&BDADDR(index)); + if (!adapter) { + error("Unable to find matching adapter"); + return; + } + + if (evt->link_type != ACL_LINK) + return; + +- btd_event_conn_complete(sba, evt->status, btohs(evt->handle), +- &evt->bdaddr); ++ btd_event_conn_complete(&BDADDR(index), evt->status, ++ btohs(evt->handle), &evt->bdaddr); + + if (evt->status) + return; + +- update_lastused(sba, &evt->bdaddr); ++ update_lastused(&BDADDR(index), &evt->bdaddr); + + /* check if the remote version needs be requested */ +- ba2str(sba, local_addr); ++ ba2str(&BDADDR(index), local_addr); + ba2str(&evt->bdaddr, peer_addr); + + create_name(filename, sizeof(filename), STORAGEDIR, local_addr, + "manufacturers"); + +@@ -955,46 +966,47 @@ static inline void conn_complete(int dev + TRUE); + else + free(str); + } + +-static inline void disconn_complete(int dev, bdaddr_t *sba, void *ptr) ++static inline void disconn_complete(int index, void *ptr) + { + evt_disconn_complete *evt = ptr; + +- btd_event_disconn_complete(sba, evt->status, btohs(evt->handle), +- evt->reason); ++ btd_event_disconn_complete(&BDADDR(index), evt->status, ++ btohs(evt->handle), evt->reason); + } + +-static inline void auth_complete(int dev, bdaddr_t *sba, void *ptr) ++static inline void auth_complete(int index, void *ptr) + { + evt_auth_complete *evt = ptr; + bdaddr_t dba; + +- if (get_bdaddr(dev, sba, btohs(evt->handle), &dba) < 0) ++ if (get_bdaddr(index, btohs(evt->handle), &dba) < 0) + return; + +- btd_event_bonding_process_complete(sba, &dba, evt->status); ++ btd_event_bonding_process_complete(&BDADDR(index), &dba, evt->status); + } + +-static inline void simple_pairing_complete(int dev, bdaddr_t *sba, void *ptr) ++static inline void simple_pairing_complete(int index, void *ptr) + { + evt_simple_pairing_complete *evt = ptr; + +- btd_event_simple_pairing_complete(sba, &evt->bdaddr, evt->status); ++ btd_event_simple_pairing_complete(&BDADDR(index), &evt->bdaddr, ++ evt->status); + } + +-static inline void conn_request(int dev, bdaddr_t *sba, void *ptr) ++static inline void conn_request(int index, void *ptr) + { + evt_conn_request *evt = ptr; + uint32_t class = evt->dev_class[0] | (evt->dev_class[1] << 8) + | (evt->dev_class[2] << 16); + +- btd_event_remote_class(sba, &evt->bdaddr, class); ++ btd_event_remote_class(&BDADDR(index), &evt->bdaddr, class); + } + +-static inline void le_metaevent(int dev, bdaddr_t *sba, void *ptr) ++static inline void le_metaevent(int index, void *ptr) + { + evt_le_meta_event *meta = ptr; + le_advertising_info *info; + uint8_t *rssi, num, i; + +@@ -1007,65 +1019,51 @@ static inline void le_metaevent(int dev, + info = (le_advertising_info *) (meta->data + 1); + + for (i = 0; i < num; i++) { + /* RSSI is last byte of the advertising report event */ + rssi = info->data + info->length; +- btd_event_inquiry_result(sba, &info->bdaddr, 0, *rssi, NULL); ++ btd_event_inquiry_result(&BDADDR(index), &info->bdaddr, 0, ++ *rssi, NULL); + info = (le_advertising_info *) (rssi + 1); + } + } + +-static void stop_hci_dev(int hdev) ++static void stop_hci_dev(int index) + { +- GIOChannel *chan = io_data[hdev].channel; ++ GIOChannel *chan = CHANNEL(index); + + if (!chan) + return; + +- info("Stopping hci%d event socket", hdev); +- +- g_source_remove(io_data[hdev].watch_id); +- g_io_channel_unref(io_data[hdev].channel); +- io_data[hdev].watch_id = -1; +- io_data[hdev].channel = NULL; +- io_data[hdev].pin_length = -1; +-} +- +-static void delete_channel(GIOChannel *chan) +-{ +- int i; +- +- /* Look for the GIOChannel in the table */ +- for (i = 0; i < HCI_MAX_DEV; i++) +- if (io_data[i].channel == chan) { +- stop_hci_dev(i); +- return; +- } ++ info("Stopping hci%d event socket", index); + +- error("IO channel not found in the io_data table"); ++ g_source_remove(WATCH_ID(index)); ++ g_io_channel_unref(CHANNEL(index)); ++ hci_close_dev(SK(index)); ++ init_dev_info(index, -1); + } + + 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; ++ int type, index = GPOINTER_TO_INT(data); ++ struct hci_dev_info di; + 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); ++ stop_hci_dev(index); + 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); ++ stop_hci_dev(index); + return FALSE; + } + + type = *ptr++; + +@@ -1073,143 +1071,135 @@ static gboolean io_security_event(GIOCha + 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); ++ memset(&di, 0, sizeof(di)); ++ if (hci_devinfo(index, &di) == 0) { ++ bacpy(&BDADDR(index), &di.bdaddr); + +- if (ignore_device(di)) +- return TRUE; ++ if (ignore_device(&di)) ++ return TRUE; ++ } + + switch (eh->evt) { + case EVT_CMD_STATUS: +- cmd_status(dev, &di->bdaddr, ptr); ++ cmd_status(index, ptr); + break; + + case EVT_CMD_COMPLETE: +- cmd_complete(dev, &di->bdaddr, ptr); ++ cmd_complete(index, ptr); + break; + + case EVT_REMOTE_NAME_REQ_COMPLETE: +- remote_name_information(dev, &di->bdaddr, ptr); ++ remote_name_information(index, ptr); + break; + + case EVT_READ_REMOTE_VERSION_COMPLETE: +- remote_version_information(dev, &di->bdaddr, ptr); ++ remote_version_information(index, ptr); + break; + + case EVT_READ_REMOTE_FEATURES_COMPLETE: +- remote_features_information(dev, &di->bdaddr, ptr); ++ remote_features_information(index, ptr); + break; + + case EVT_REMOTE_HOST_FEATURES_NOTIFY: +- remote_features_notify(dev, &di->bdaddr, ptr); ++ remote_features_notify(index, ptr); + break; + + case EVT_INQUIRY_COMPLETE: + evt = (evt_cmd_status *) ptr; +- inquiry_complete(&di->bdaddr, evt->status, FALSE); ++ inquiry_complete(&BDADDR(index), evt->status, FALSE); + break; + + case EVT_INQUIRY_RESULT: +- inquiry_result(dev, &di->bdaddr, eh->plen, ptr); ++ inquiry_result(index, eh->plen, ptr); + break; + + case EVT_INQUIRY_RESULT_WITH_RSSI: +- inquiry_result_with_rssi(dev, &di->bdaddr, eh->plen, ptr); ++ inquiry_result_with_rssi(index, eh->plen, ptr); + break; + + case EVT_EXTENDED_INQUIRY_RESULT: +- extended_inquiry_result(dev, &di->bdaddr, eh->plen, ptr); ++ extended_inquiry_result(index, eh->plen, ptr); + break; + + case EVT_CONN_COMPLETE: +- conn_complete(dev, di->dev_id, &di->bdaddr, ptr); ++ conn_complete(index, ptr); + break; + + case EVT_DISCONN_COMPLETE: +- disconn_complete(dev, &di->bdaddr, ptr); ++ disconn_complete(index, ptr); + break; + + case EVT_AUTH_COMPLETE: +- auth_complete(dev, &di->bdaddr, ptr); ++ auth_complete(index, ptr); + break; + + case EVT_SIMPLE_PAIRING_COMPLETE: +- simple_pairing_complete(dev, &di->bdaddr, ptr); ++ simple_pairing_complete(index, ptr); + break; + + case EVT_CONN_REQUEST: +- conn_request(dev, &di->bdaddr, ptr); ++ conn_request(index, ptr); + break; + case EVT_LE_META_EVENT: +- le_metaevent(dev, &di->bdaddr, ptr); ++ le_metaevent(index, ptr); + break; + case EVT_PIN_CODE_REQ: +- pin_code_request(dev, &di->bdaddr, (bdaddr_t *) ptr); ++ pin_code_request(index, (bdaddr_t *) ptr); + break; + + case EVT_LINK_KEY_REQ: +- link_key_request(dev, &di->bdaddr, (bdaddr_t *) ptr); ++ link_key_request(index, (bdaddr_t *) ptr); + break; + + case EVT_LINK_KEY_NOTIFY: +- link_key_notify(dev, &di->bdaddr, ptr); ++ link_key_notify(index, ptr); + break; + + case EVT_RETURN_LINK_KEYS: +- return_link_keys(dev, &di->bdaddr, ptr); ++ return_link_keys(index, ptr); + break; + + case EVT_IO_CAPABILITY_REQUEST: +- io_capa_request(dev, &di->bdaddr, (bdaddr_t *) ptr); ++ io_capa_request(index, ptr); + break; + + case EVT_IO_CAPABILITY_RESPONSE: +- io_capa_response(dev, &di->bdaddr, ptr); ++ io_capa_response(index, ptr); + break; + + case EVT_USER_CONFIRM_REQUEST: +- user_confirm_request(dev, &di->bdaddr, ptr); ++ user_confirm_request(index, ptr); + break; + + case EVT_USER_PASSKEY_REQUEST: +- user_passkey_request(dev, &di->bdaddr, ptr); ++ user_passkey_request(index, ptr); + break; + + case EVT_USER_PASSKEY_NOTIFY: +- user_passkey_notify(dev, &di->bdaddr, ptr); ++ user_passkey_notify(index, ptr); + break; + + case EVT_REMOTE_OOB_DATA_REQUEST: +- remote_oob_data_request(dev, &di->bdaddr, ptr); ++ remote_oob_data_request(index, ptr); + break; + } + + return TRUE; + } + +-static void init_hci_dev(int hdev) ++static void start_hci_dev(int index) + { +- GIOChannel *chan = io_data[hdev].channel; +- struct hci_dev_info *di; ++ GIOChannel *chan = CHANNEL(index); + 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; +- } ++ info("Listening for HCI events on hci%d", index); + + /* Set filter */ + hci_filter_clear(&flt); + hci_filter_set_ptype(HCI_EVENT_PKT, &flt); + hci_filter_set_event(EVT_CMD_STATUS, &flt); +@@ -1237,42 +1227,24 @@ static void init_hci_dev(int hdev) + 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, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) { ++ if (setsockopt(SK(index), 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); ++ index, strerror(errno), errno); + 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, ++ chan = g_io_channel_unix_new(SK(index)); ++ WATCH_ID(index) = g_io_add_watch_full(chan, G_PRIORITY_LOW, + G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR, +- io_security_event, di, (GDestroyNotify) g_free); +- io_data[hdev].channel = chan; +- io_data[hdev].pin_length = -1; +- +- if (ignore_device(di)) +- return; ++ io_security_event, GINT_TO_POINTER(index), ++ NULL); ++ CHANNEL(index) = chan; ++ PIN_LENGTH(index) = -1; + +- 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); + } + + /* End of HCI event callbacks */ + + static gboolean child_exit(GIOChannel *io, GIOCondition cond, void *user_data) +@@ -1303,10 +1275,11 @@ static void at_child_exit(void) + + static void device_devup_setup(int index) + { + struct hci_dev_info di; + uint16_t policy; ++ read_stored_link_key_cp cp; + + if (hci_devinfo(index, &di) < 0) + return; + + if (ignore_device(&di)) +@@ -1326,15 +1299,17 @@ static void device_devup_setup(int index + /* Set default link policy */ + policy = htobs(main_opts.link_policy); + hci_send_cmd(SK(index), OGF_LINK_POLICY, + OCF_WRITE_DEFAULT_LINK_POLICY, 2, &policy); + +- init_hci_dev(index); ++ bacpy(&cp.bdaddr, BDADDR_ANY); ++ cp.read_all = 1; ++ hci_send_cmd(SK(index), OGF_HOST_CTL, OCF_READ_STORED_LINK_KEY, ++ READ_STORED_LINK_KEY_CP_SIZE, (void *) &cp); + +- /* Return value 1 means ioctl(DEVDOWN) was performed */ +- if (manager_start_adapter(index) == 1) +- stop_hci_dev(index); ++ if (READY(index)) ++ manager_start_adapter(index); + } + + static void init_device(int index) + { + struct hci_dev_req dr; +@@ -1353,10 +1328,11 @@ static void init_device(int index) + max_dev = index; + devs = g_realloc(devs, sizeof(devs[0]) * (max_dev + 1)); + } + + init_dev_info(index, dd); ++ start_hci_dev(index); + + /* Do initialization in the separate process */ + pid = fork(); + switch (pid) { + case 0: +@@ -1433,24 +1409,27 @@ static void device_event(int event, int + device_devreg_setup(index); + break; + + case HCI_DEV_UNREG: + info("HCI dev %d unregistered", index); +- hci_close_dev(SK(index)); +- init_dev_info(index, -1); ++ stop_hci_dev(index); + manager_unregister_adapter(index); + break; + + case HCI_DEV_UP: + info("HCI dev %d up", index); ++ UP(index) = TRUE; + device_devup_setup(index); + break; + + case HCI_DEV_DOWN: + info("HCI dev %d down", index); +- manager_stop_adapter(index); +- stop_hci_dev(index); ++ UP(index) = FALSE; ++ if (READY(index)) { ++ manager_stop_adapter(index); ++ READY(index) = FALSE; ++ } + break; + } + } + + static gboolean init_known_adapters(gpointer user_data) +@@ -2140,10 +2119,12 @@ static int hciops_pincode_reply(int inde + + if (pin) { + pin_code_reply_cp pr; + size_t len = strlen(pin); + ++ PIN_LENGTH(index) = len; ++ + memset(&pr, 0, sizeof(pr)); + bacpy(&pr.bdaddr, bdaddr); + memcpy(pr.pin_code, pin, len); + pr.pin_len = len; + err = hci_send_cmd(SK(index), OGF_LINK_CTL, +Index: b/plugins/mgmtops.c +=================================================================== +--- a/plugins/mgmtops.c ++++ b/plugins/mgmtops.c +@@ -66,13 +66,13 @@ static uint8_t mgmt_version = 0; + static uint16_t mgmt_revision = 0; + + static void read_version_complete(int sk, void *buf, size_t len) + { + struct mgmt_hdr hdr; +- struct mgmt_read_version_rp *rp = buf; ++ struct mgmt_rp_read_version *rp = buf; + +- if (len < MGMT_READ_VERSION_RP_SIZE) { ++ if (len < sizeof(*rp)) { + error("Too small read version complete event"); + return; + } + + mgmt_revision = btohs(bt_get_unaligned(&rp->revision)); +@@ -96,17 +96,19 @@ static void add_controller(uint16_t inde + } + + memset(&controllers[index], 0, sizeof(struct controller_info)); + + controllers[index].valid = TRUE; ++ ++ DBG("Added controller %u", index); + } + + static void read_info(int sk, uint16_t index) + { +- char buf[MGMT_HDR_SIZE + MGMT_READ_INFO_CP_SIZE]; ++ char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_read_info)]; + struct mgmt_hdr *hdr = (void *) buf; +- struct mgmt_read_info_cp *cp = (void *) &buf[sizeof(*hdr)]; ++ struct mgmt_cp_read_info *cp = (void *) &buf[sizeof(*hdr)]; + + memset(buf, 0, sizeof(buf)); + hdr->opcode = MGMT_OP_READ_INFO; + hdr->len = htobs(sizeof(*cp)); + +@@ -115,15 +117,61 @@ static void read_info(int sk, uint16_t i + if (write(sk, buf, sizeof(buf)) < 0) + error("Unable to send read_info command: %s (%d)", + strerror(errno), errno); + } + ++static void mgmt_index_added(int sk, void *buf, size_t len) ++{ ++ struct mgmt_ev_index_added *ev = buf; ++ uint16_t index; ++ ++ if (len < sizeof(*ev)) { ++ error("Too small index added event"); ++ return; ++ } ++ ++ index = btohs(bt_get_unaligned(&ev->index)); ++ ++ add_controller(index); ++ read_info(sk, index); ++} ++ ++static void remove_controller(uint16_t index) ++{ ++ if (index > max_index) ++ return; ++ ++ if (!controllers[index].valid) ++ return; ++ ++ manager_unregister_adapter(index); ++ ++ memset(&controllers[index], 0, sizeof(struct controller_info)); ++ ++ DBG("Removed controller %u", index); ++} ++ ++static void mgmt_index_removed(int sk, void *buf, size_t len) ++{ ++ struct mgmt_ev_index_removed *ev = buf; ++ uint16_t index; ++ ++ if (len < sizeof(*ev)) { ++ error("Too small index removed event"); ++ return; ++ } ++ ++ index = btohs(bt_get_unaligned(&ev->index)); ++ ++ remove_controller(index); ++} ++ + static void read_mode(int sk, uint16_t index) + { +- char buf[MGMT_HDR_SIZE + MGMT_READ_MODE_CP_SIZE]; ++ char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_read_mode)]; + struct mgmt_hdr *hdr = (void *) buf; +- struct mgmt_read_mode_cp *cp = (void *) &buf[sizeof(*hdr)]; ++ struct mgmt_cp_read_mode *cp = (void *) &buf[sizeof(*hdr)]; + + memset(buf, 0, sizeof(buf)); + hdr->opcode = MGMT_OP_READ_MODE; + hdr->len = htobs(sizeof(*cp)); + +@@ -134,46 +182,44 @@ static void read_mode(int sk, uint16_t i + strerror(errno), errno); + } + + static void read_index_list_complete(int sk, void *buf, size_t len) + { +- struct mgmt_read_index_list_rp *rp = buf; ++ struct mgmt_rp_read_index_list *rp = buf; + uint16_t num; + int i; + +- if (len < MGMT_READ_INDEX_LIST_RP_SIZE) { ++ if (len < sizeof(*rp)) { + error("Too small read index list complete event"); + return; + } + + num = btohs(bt_get_unaligned(&rp->num_controllers)); + +- if (num * sizeof(uint16_t) + MGMT_READ_INDEX_LIST_RP_SIZE != len) { ++ if (num * sizeof(uint16_t) + sizeof(*rp) != len) { + error("Incorrect packet size for index list event"); + return; + } + + for (i = 0; i < num; i++) { + uint16_t index; + + index = btohs(bt_get_unaligned(&rp->index[i])); + +- DBG("Found controller %u", index); +- + add_controller(index); + read_info(sk, index); + } + } + + static void read_info_complete(int sk, void *buf, size_t len) + { +- struct mgmt_read_info_rp *rp = buf; ++ struct mgmt_rp_read_info *rp = buf; + struct controller_info *info; + uint16_t index; + char addr[18]; + +- if (len < MGMT_READ_INFO_RP_SIZE) { ++ if (len < sizeof(*rp)) { + error("Too small read info complete event"); + return; + } + + if (rp->status != 0) { +@@ -199,17 +245,17 @@ static void read_info_complete(int sk, v + read_mode(sk, index); + } + + static void read_mode_complete(int sk, void *buf, size_t len) + { +- struct mgmt_read_mode_rp *rp = buf; ++ struct mgmt_rp_read_mode *rp = buf; + struct controller_info *info; + uint16_t index; + +- if (len < MGMT_READ_MODE_RP_SIZE) { +- error("Too small read mode complete event (%zu != %d)", +- len, MGMT_READ_MODE_RP_SIZE); ++ if (len < sizeof(*rp)) { ++ error("Too small read mode complete event (%zu != %zu)", ++ len, sizeof(*rp)); + return; + } + + if (rp->status != 0) { + error("Reading controller mode failed: %s (%u)", +@@ -226,15 +272,17 @@ static void read_mode_complete(int sk, v + info = &controllers[index]; + info->enabled = rp->enabled ? TRUE : FALSE; + info->mode = rp->mode; + + DBG("hci%u enabled %u mode %u", index, info->enabled, info->mode); ++ ++ manager_register_adapter(index, info->enabled); + } + + static void mgmt_cmd_complete(int sk, void *buf, size_t len) + { +- struct mgmt_cmd_complete_ev *ev = buf; ++ struct mgmt_ev_cmd_complete *ev = buf; + uint16_t opcode; + + DBG(""); + + if (len < sizeof(*ev)) { +@@ -263,16 +311,36 @@ static void mgmt_cmd_complete(int sk, vo + } + } + + static void mgmt_cmd_status(int sk, void *buf, size_t len) + { +- DBG(""); ++ struct mgmt_ev_cmd_status *ev = buf; ++ uint16_t opcode; ++ ++ if (len < sizeof(*ev)) { ++ error("Too small management command status event packet"); ++ return; ++ } ++ ++ opcode = btohs(bt_get_unaligned(&ev->opcode)); ++ ++ DBG("status %u opcode %u", ev->status, opcode); + } + + static void mgmt_controller_error(int sk, void *buf, size_t len) + { +- DBG(""); ++ struct mgmt_ev_controller_error *ev = buf; ++ uint16_t index; ++ ++ if (len < sizeof(*ev)) { ++ error("Too small management controller error event packet"); ++ return; ++ } ++ ++ index = btohs(bt_get_unaligned(&ev->index)); ++ ++ DBG("index %u error_code %u", index, ev->error_code); + } + + static gboolean mgmt_event(GIOChannel *io, GIOCondition cond, gpointer user_data) + { + char buf[MGMT_BUF_SIZE]; +@@ -323,10 +391,16 @@ static gboolean mgmt_event(GIOChannel *i + mgmt_cmd_status(sk, buf + MGMT_HDR_SIZE, len); + break; + case MGMT_EV_CONTROLLER_ERROR: + mgmt_controller_error(sk, buf + MGMT_HDR_SIZE, len); + break; ++ case MGMT_EV_INDEX_ADDED: ++ mgmt_index_added(sk, buf + MGMT_HDR_SIZE, len); ++ break; ++ case MGMT_EV_INDEX_REMOVED: ++ mgmt_index_removed(sk, buf + MGMT_HDR_SIZE, len); ++ break; + default: + error("Unknown Management opcode %u", opcode); + break; + } + +Index: b/src/agent.c +=================================================================== +--- a/src/agent.c ++++ b/src/agent.c +@@ -409,12 +409,10 @@ static void pincode_reply(DBusPendingCal + cb(agent, &err, NULL, req->user_data); + dbus_error_free(&err); + goto done; + } + +- set_pin_length(&sba, len); +- + cb(agent, NULL, pin, req->user_data); + + done: + if (message) + dbus_message_unref(message); +Index: b/src/event.c +=================================================================== +--- a/src/event.c ++++ b/src/event.c +@@ -114,19 +114,18 @@ static void pincode_cb(struct agent *age + err = btd_adapter_pincode_reply(adapter, &dba, pincode); + if (err < 0) + goto fail; + + adapter_get_address(adapter, &sba); +- set_pin_length(&sba, strlen(pincode)); + + return; + + fail: + error("Sending PIN code reply failed: %s (%d)", strerror(-err), -err); + } + +-int btd_event_request_pin(int dev, bdaddr_t *sba, struct hci_conn_info *ci) ++int btd_event_request_pin(bdaddr_t *sba, struct hci_conn_info *ci) + { + struct btd_adapter *adapter; + struct btd_device *device; + + if (!get_adapter_and_device(sba, &ci->bdaddr, &adapter, &device, TRUE)) +Index: b/src/event.h +=================================================================== +--- a/src/event.h ++++ b/src/event.h +@@ -20,11 +20,11 @@ + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +-int btd_event_request_pin(int dev, bdaddr_t *sba, struct hci_conn_info *ci); ++int btd_event_request_pin(bdaddr_t *sba, struct hci_conn_info *ci); + void btd_event_inquiry_result(bdaddr_t *local, bdaddr_t *peer, uint32_t class, int8_t rssi, uint8_t *data); + void btd_event_set_legacy_pairing(bdaddr_t *local, bdaddr_t *peer, gboolean legacy); + void btd_event_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class); + void btd_event_remote_name(bdaddr_t *local, bdaddr_t *peer, uint8_t status, char *name); + void btd_event_conn_complete(bdaddr_t *local, uint8_t status, uint16_t handle, bdaddr_t *peer); +Index: b/src/hcid.h +=================================================================== +--- a/src/hcid.h ++++ b/src/hcid.h +@@ -75,12 +75,10 @@ enum { + extern struct main_opts main_opts; + + void btd_start_exit_timer(void); + void btd_stop_exit_timer(void); + +-void set_pin_length(bdaddr_t *sba, int length); +- + gboolean plugin_init(GKeyFile *config, const char *enable, + const char *disable); + void plugin_cleanup(void); + + void rfkill_init(void); diff --git a/bluez-gstreamer.changes b/bluez-gstreamer.changes index 4970205..16e8779 100644 --- a/bluez-gstreamer.changes +++ b/bluez-gstreamer.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Mon Nov 8 09:32:16 UTC 2010 - seife@opensuse.org + +- patch to current git to fix race condition in hciops causing + adapter detection to fail + ------------------------------------------------------------------- Sun Nov 7 09:32:52 UTC 2010 - seife@opensuse.org diff --git a/bluez-gstreamer.spec b/bluez-gstreamer.spec index 3b9b6c6..4203715 100644 --- a/bluez-gstreamer.spec +++ b/bluez-gstreamer.spec @@ -40,6 +40,7 @@ Source3: bluetooth.sysconfig Source4: bluetooth.sh Source6: README.SUSE Patch1: bluez-4.75-udev-use-helperscript.diff +Patch99: bluez-4.78-cc758c498ed98de11e890e56d4500ca85587bc07.diff BuildRoot: %{_tmppath}/%{name}-%{version}-build Requires: libbluetooth3 = %{version} Provides: bluez-audio:%_libdir/gstreamer-0.10/libgstbluetooth.so @@ -64,6 +65,7 @@ Authors: %prep %setup -n bluez-%{version} -q %patch1 -p1 +%patch99 -p1 cp %{S:6} . %{?suse_update_config:%{suse_update_config -f . }} diff --git a/bluez.changes b/bluez.changes index 4970205..16e8779 100644 --- a/bluez.changes +++ b/bluez.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Mon Nov 8 09:32:16 UTC 2010 - seife@opensuse.org + +- patch to current git to fix race condition in hciops causing + adapter detection to fail + ------------------------------------------------------------------- Sun Nov 7 09:32:52 UTC 2010 - seife@opensuse.org diff --git a/bluez.spec b/bluez.spec index 0d43b41..0e5a436 100644 --- a/bluez.spec +++ b/bluez.spec @@ -42,6 +42,7 @@ Source6: README.SUSE Source7: bluetooth.modprobe Patch1: bluez-4.75-udev-use-helperscript.diff Patch2: 001-remove-rule-dell-mouse.patch +Patch99: bluez-4.78-cc758c498ed98de11e890e56d4500ca85587bc07.diff # needed until next upstream release --seife BuildRoot: %{_tmppath}/%{name}-%{version}-build Provides: bluez-utils = 3.36 @@ -181,6 +182,7 @@ Authors: %setup -q %patch1 -p1 %patch2 -p1 +%patch99 -p1 cp %{S:6} . %{?suse_update_config:%{suse_update_config -f . }} mkdir dbus-apis