HCI_AUTO_CONN_DIRECT_REPORT_IND (associated to a new autoconnect action, 0x03) treats advertising reports like a combination of HCI_AUTO_CONN_DIRECT and HCI_AUTO_CONN_REPORT: * Autoconnects on ADV_DIRECT_IND reports. * Notifies userland (MGMT_EV_DEVICE_FOUND) about ADV_IND reports. This is useful to communicate with autoconnectable devices which advertise meaningful ADV_IND reports. HCI_AUTO_CONN_DIRECT_REPORT_IND requires being able to simultaneously have a pending report and connection action. I merged pend_le_reports and pend_le_conns into the new pend_le_actions in order to make that possible while maintaining a unique list_head in hci_conn_parameters (action). This results in simpler handling of pending actions. Signed-off-by: Alfonso Acosta <fons@xxxxxxxxxxx> --- include/net/bluetooth/hci_core.h | 6 ++--- net/bluetooth/hci_conn.c | 2 +- net/bluetooth/hci_core.c | 54 ++++++++++------------------------------ net/bluetooth/hci_event.c | 24 ++++++++++++------ net/bluetooth/mgmt.c | 30 ++++++++++++++++------ 5 files changed, 56 insertions(+), 60 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 37ff1ae..59393ea 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -317,8 +317,7 @@ struct hci_dev { struct list_head remote_oob_data; struct list_head le_white_list; struct list_head le_conn_params; - struct list_head pend_le_conns; - struct list_head pend_le_reports; + struct list_head pend_le_actions; struct hci_dev_stats stat; @@ -461,6 +460,7 @@ struct hci_conn_params { HCI_AUTO_CONN_DISABLED, HCI_AUTO_CONN_REPORT, HCI_AUTO_CONN_DIRECT, + HCI_AUTO_CONN_DIRECT_REPORT_IND, HCI_AUTO_CONN_ALWAYS, HCI_AUTO_CONN_LINK_LOSS, } auto_connect; @@ -881,7 +881,7 @@ void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); void hci_conn_params_clear_all(struct hci_dev *hdev); void hci_conn_params_clear_disabled(struct hci_dev *hdev); -struct hci_conn_params *hci_pend_le_action_lookup(struct list_head *list, +struct hci_conn_params *hci_pend_le_action_lookup(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index b9517bd..f65b705 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -596,7 +596,7 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status) struct hci_dev *hdev = conn->hdev; struct hci_conn_params *params; - params = hci_pend_le_action_lookup(&hdev->pend_le_conns, &conn->dst, + params = hci_pend_le_action_lookup(&hdev->pend_le_actions, &conn->dst, conn->dst_type); if (params && params->conn) { hci_conn_drop(params->conn); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index cb05d7f..980ec2e 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3631,7 +3631,7 @@ static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type) } /* This function requires the caller holds hdev->lock */ -struct hci_conn_params *hci_pend_le_action_lookup(struct list_head *list, +struct hci_conn_params *hci_pend_le_action_lookup(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) { struct hci_conn_params *param; @@ -3640,7 +3640,7 @@ struct hci_conn_params *hci_pend_le_action_lookup(struct list_head *list, if (!hci_is_identity_address(addr, addr_type)) return NULL; - list_for_each_entry(param, list, action) { + list_for_each_entry(param, &hdev->pend_le_actions, action) { if (bacmp(¶m->addr, addr) == 0 && param->addr_type == addr_type) return param; @@ -3706,13 +3706,14 @@ int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, hci_update_background_scan(hdev); break; case HCI_AUTO_CONN_REPORT: - list_add(¶ms->action, &hdev->pend_le_reports); + case HCI_AUTO_CONN_DIRECT_REPORT_IND: + list_add(¶ms->action, &hdev->pend_le_actions); hci_update_background_scan(hdev); break; case HCI_AUTO_CONN_DIRECT: case HCI_AUTO_CONN_ALWAYS: if (!is_connected(hdev, addr, addr_type)) { - list_add(¶ms->action, &hdev->pend_le_conns); + list_add(¶ms->action, &hdev->pend_le_actions); hci_update_background_scan(hdev); } break; @@ -4020,8 +4021,7 @@ struct hci_dev *hci_alloc_dev(void) INIT_LIST_HEAD(&hdev->remote_oob_data); INIT_LIST_HEAD(&hdev->le_white_list); INIT_LIST_HEAD(&hdev->le_conn_params); - INIT_LIST_HEAD(&hdev->pend_le_conns); - INIT_LIST_HEAD(&hdev->pend_le_reports); + INIT_LIST_HEAD(&hdev->pend_le_actions); INIT_LIST_HEAD(&hdev->conn_hash.list); INIT_WORK(&hdev->rx_work, hci_rx_work); @@ -5467,16 +5467,13 @@ static u8 update_white_list(struct hci_request *req) /* Go through the current white list programmed into the * controller one by one and check if that address is still - * in the list of pending connections or list of devices to - * report. If not present in either list, then queue the - * command to remove it from the controller. + * in the list of pending actions list. If not present, + * then queue the command to remove it from the controller. */ list_for_each_entry(b, &hdev->le_white_list, list) { struct hci_cp_le_del_from_white_list cp; - if (hci_pend_le_action_lookup(&hdev->pend_le_conns, - &b->bdaddr, b->bdaddr_type) || - hci_pend_le_action_lookup(&hdev->pend_le_reports, + if (hci_pend_le_action_lookup(hdev, &b->bdaddr, b->bdaddr_type)) { white_list_entries++; continue; @@ -5490,7 +5487,7 @@ static u8 update_white_list(struct hci_request *req) } /* Since all no longer valid white list entries have been - * removed, walk through the list of pending connections + * removed, walk through the list of pending actions * and ensure that any new device gets programmed into * the controller. * @@ -5499,31 +5496,7 @@ static u8 update_white_list(struct hci_request *req) * just abort and return filer policy value to not use the * white list. */ - list_for_each_entry(params, &hdev->pend_le_conns, action) { - if (hci_bdaddr_list_lookup(&hdev->le_white_list, - ¶ms->addr, params->addr_type)) - continue; - - if (white_list_entries >= hdev->le_white_list_size) { - /* Select filter policy to accept all advertising */ - return 0x00; - } - - if (hci_find_irk_by_addr(hdev, ¶ms->addr, - params->addr_type)) { - /* White list can not be used with RPAs */ - return 0x00; - } - - white_list_entries++; - add_to_white_list(req, params); - } - - /* After adding all new pending connections, walk through - * the list of pending reports and also add these to the - * white list if there is still space. - */ - list_for_each_entry(params, &hdev->pend_le_reports, action) { + list_for_each_entry(params, &hdev->pend_le_actions, action) { if (hci_bdaddr_list_lookup(&hdev->le_white_list, ¶ms->addr, params->addr_type)) continue; @@ -5593,7 +5566,7 @@ static void update_background_scan_complete(struct hci_dev *hdev, u8 status) "status 0x%2.2x", status); } -/* This function controls the background scanning based on hdev->pend_le_conns +/* This function controls the background scanning based on hdev->pend_le_actions * list. If there are pending LE connection we start the background scanning, * otherwise we stop it. * @@ -5623,8 +5596,7 @@ void hci_update_background_scan(struct hci_dev *hdev) hci_req_init(&req, hdev); - if (list_empty(&hdev->pend_le_conns) && - list_empty(&hdev->pend_le_reports)) { + if (list_empty(&hdev->pend_le_actions)) { /* If there is no pending LE connections or devices * to be scanned for, we should stop the background * scanning. diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 8b0a2a6..3d669da 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2265,9 +2265,10 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) /* Fall through */ case HCI_AUTO_CONN_DIRECT: + case HCI_AUTO_CONN_DIRECT_REPORT_IND: case HCI_AUTO_CONN_ALWAYS: list_del_init(¶ms->action); - list_add(¶ms->action, &hdev->pend_le_conns); + list_add(¶ms->action, &hdev->pend_le_actions); hci_update_background_scan(hdev); break; @@ -4292,13 +4293,13 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, /* If we're not connectable only connect devices that we have in * our pend_le_conns list. */ - params = hci_pend_le_action_lookup(&hdev->pend_le_conns, - addr, addr_type); + params = hci_pend_le_action_lookup(hdev, addr, addr_type); if (!params) return; switch (params->auto_connect) { case HCI_AUTO_CONN_DIRECT: + case HCI_AUTO_CONN_DIRECT_REPORT_IND: /* Only devices advertising with ADV_DIRECT_IND are * triggering a connection attempt. This is allowing * incoming connections from slave devices. @@ -4351,6 +4352,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, struct smp_irk *irk; bool match; u32 flags; + struct hci_conn_params *params; /* Check if we need to convert to identity address */ irk = hci_get_irk(hdev, bdaddr, bdaddr_type); @@ -4363,17 +4365,25 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, check_pending_le_conn(hdev, bdaddr, bdaddr_type, type); /* Passive scanning shouldn't trigger any device found events, - * except for devices marked as CONN_REPORT for which we do send - * device found events. + * except for devices marked as CONN_REPORT or CONN_DIRECT_REPORT_IND + * for which we do send device found events. */ if (hdev->le_scan_type == LE_SCAN_PASSIVE) { if (type == LE_ADV_DIRECT_IND) return; - if (!hci_pend_le_action_lookup(&hdev->pend_le_reports, - bdaddr, bdaddr_type)) + params = hci_pend_le_action_lookup(hdev, bdaddr, bdaddr_type); + if (!params) return; + switch (params->auto_connect) { + case HCI_AUTO_CONN_REPORT: + case HCI_AUTO_CONN_DIRECT_REPORT_IND: + break; + default: + return; + } + if (type == LE_ADV_NONCONN_IND || type == LE_ADV_SCAN_IND) flags = MGMT_DEV_FOUND_NOT_CONNECTABLE; else diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index efb71b0..adb5248 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5241,7 +5241,7 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, MGMT_STATUS_INVALID_PARAMS, &cp->addr, sizeof(cp->addr)); - if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02) + if (cp->action > 0x03) return cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, MGMT_STATUS_INVALID_PARAMS, &cp->addr, sizeof(cp->addr)); @@ -5272,7 +5272,9 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, else addr_type = ADDR_LE_DEV_RANDOM; - if (cp->action == 0x02) + if (cp->action == 0x03) + auto_conn = HCI_AUTO_CONN_DIRECT_REPORT_IND; + else if (cp->action == 0x02) auto_conn = HCI_AUTO_CONN_ALWAYS; else if (cp->action == 0x01) auto_conn = HCI_AUTO_CONN_DIRECT; @@ -5838,10 +5840,9 @@ static void restart_le_actions(struct hci_dev *hdev) switch (p->auto_connect) { case HCI_AUTO_CONN_DIRECT: case HCI_AUTO_CONN_ALWAYS: - list_add(&p->action, &hdev->pend_le_conns); - break; + case HCI_AUTO_CONN_DIRECT_REPORT_IND: case HCI_AUTO_CONN_REPORT: - list_add(&p->action, &hdev->pend_le_reports); + list_add(&p->action, &hdev->pend_le_actions); break; default: break; @@ -6746,16 +6747,29 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, char buf[512]; struct mgmt_ev_device_found *ev = (void *) buf; size_t ev_size; + struct hci_conn_params *params; /* Don't send events for a non-kernel initiated discovery. With - * LE one exception is if we have pend_le_reports > 0 in which + * LE one exception is if we have CONN_REPORT in pend_le_actions in which * case we're doing passive scanning and want these events. */ if (!hci_discovery_active(hdev)) { if (link_type == ACL_LINK) return; - if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports)) - return; + if (link_type == LE_LINK) + { + params = hci_conn_params_lookup(hdev, bdaddr, addr_type); + if(!params) + return; + switch(params->auto_connect) + { + case HCI_AUTO_CONN_REPORT: + case HCI_AUTO_CONN_DIRECT_REPORT_IND: + break; + default: + return; + } + } } /* Make sure that the buffer is big enough. The 5 extra bytes -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html