|
@@ -55,8 +55,12 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
|
|
|
|
|
|
BT_DBG("%s status 0x%x", hdev->name, status);
|
|
|
|
|
|
- if (status)
|
|
|
+ if (status) {
|
|
|
+ hci_dev_lock(hdev);
|
|
|
+ mgmt_stop_discovery_failed(hdev, status);
|
|
|
+ hci_dev_unlock(hdev);
|
|
|
return;
|
|
|
+ }
|
|
|
|
|
|
clear_bit(HCI_INQUIRY, &hdev->flags);
|
|
|
|
|
@@ -190,6 +194,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
|
|
|
clear_bit(HCI_RESET, &hdev->flags);
|
|
|
|
|
|
hci_req_complete(hdev, HCI_OP_RESET, status);
|
|
|
+
|
|
|
+ hdev->dev_flags = 0;
|
|
|
}
|
|
|
|
|
|
static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
|
|
@@ -494,7 +500,7 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
|
|
|
|
|
|
/* CSR 1.1 dongles does not accept any bitfield so don't try to set
|
|
|
* any event mask for pre 1.2 devices */
|
|
|
- if (hdev->lmp_ver <= 1)
|
|
|
+ if (hdev->hci_ver < BLUETOOTH_VER_1_2)
|
|
|
return;
|
|
|
|
|
|
events[4] |= 0x01; /* Flow Specification Complete */
|
|
@@ -558,7 +564,7 @@ static void hci_setup(struct hci_dev *hdev)
|
|
|
{
|
|
|
hci_setup_event_mask(hdev);
|
|
|
|
|
|
- if (hdev->lmp_ver > 1)
|
|
|
+ if (hdev->hci_ver > BLUETOOTH_VER_1_1)
|
|
|
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
|
|
|
|
|
|
if (hdev->features[6] & LMP_SIMPLE_PAIR) {
|
|
@@ -713,6 +719,21 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
|
|
|
hci_req_complete(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, rp->status);
|
|
|
}
|
|
|
|
|
|
+static void hci_cc_read_flow_control_mode(struct hci_dev *hdev,
|
|
|
+ struct sk_buff *skb)
|
|
|
+{
|
|
|
+ struct hci_rp_read_flow_control_mode *rp = (void *) skb->data;
|
|
|
+
|
|
|
+ BT_DBG("%s status 0x%x", hdev->name, rp->status);
|
|
|
+
|
|
|
+ if (rp->status)
|
|
|
+ return;
|
|
|
+
|
|
|
+ hdev->flow_ctl_mode = rp->mode;
|
|
|
+
|
|
|
+ hci_req_complete(hdev, HCI_OP_READ_FLOW_CONTROL_MODE, rp->status);
|
|
|
+}
|
|
|
+
|
|
|
static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
|
|
|
{
|
|
|
struct hci_rp_read_buffer_size *rp = (void *) skb->data;
|
|
@@ -927,6 +948,37 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
|
|
|
hci_dev_unlock(hdev);
|
|
|
}
|
|
|
|
|
|
+static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb)
|
|
|
+{
|
|
|
+ struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
|
|
|
+
|
|
|
+ BT_DBG("%s status 0x%x", hdev->name, rp->status);
|
|
|
+
|
|
|
+ hci_dev_lock(hdev);
|
|
|
+
|
|
|
+ if (test_bit(HCI_MGMT, &hdev->flags))
|
|
|
+ mgmt_user_passkey_reply_complete(hdev, &rp->bdaddr,
|
|
|
+ rp->status);
|
|
|
+
|
|
|
+ hci_dev_unlock(hdev);
|
|
|
+}
|
|
|
+
|
|
|
+static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
|
|
|
+ struct sk_buff *skb)
|
|
|
+{
|
|
|
+ struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
|
|
|
+
|
|
|
+ BT_DBG("%s status 0x%x", hdev->name, rp->status);
|
|
|
+
|
|
|
+ hci_dev_lock(hdev);
|
|
|
+
|
|
|
+ if (test_bit(HCI_MGMT, &hdev->flags))
|
|
|
+ mgmt_user_passkey_neg_reply_complete(hdev, &rp->bdaddr,
|
|
|
+ rp->status);
|
|
|
+
|
|
|
+ hci_dev_unlock(hdev);
|
|
|
+}
|
|
|
+
|
|
|
static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
|
|
|
struct sk_buff *skb)
|
|
|
{
|
|
@@ -940,6 +992,13 @@ static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
|
|
|
hci_dev_unlock(hdev);
|
|
|
}
|
|
|
|
|
|
+static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
|
|
|
+{
|
|
|
+ __u8 status = *((__u8 *) skb->data);
|
|
|
+
|
|
|
+ BT_DBG("%s status 0x%x", hdev->name, status);
|
|
|
+}
|
|
|
+
|
|
|
static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
|
|
|
struct sk_buff *skb)
|
|
|
{
|
|
@@ -956,12 +1015,16 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
|
|
|
return;
|
|
|
|
|
|
if (cp->enable == 0x01) {
|
|
|
+ set_bit(HCI_LE_SCAN, &hdev->dev_flags);
|
|
|
+
|
|
|
del_timer(&hdev->adv_timer);
|
|
|
|
|
|
hci_dev_lock(hdev);
|
|
|
hci_adv_entries_clear(hdev);
|
|
|
hci_dev_unlock(hdev);
|
|
|
} else if (cp->enable == 0x00) {
|
|
|
+ clear_bit(HCI_LE_SCAN, &hdev->dev_flags);
|
|
|
+
|
|
|
mod_timer(&hdev->adv_timer, jiffies + ADV_CLEAR_TIMEOUT);
|
|
|
}
|
|
|
}
|
|
@@ -1014,7 +1077,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
|
|
|
hci_conn_check_pending(hdev);
|
|
|
hci_dev_lock(hdev);
|
|
|
if (test_bit(HCI_MGMT, &hdev->flags))
|
|
|
- mgmt_inquiry_failed(hdev, status);
|
|
|
+ mgmt_start_discovery_failed(hdev, status);
|
|
|
hci_dev_unlock(hdev);
|
|
|
return;
|
|
|
}
|
|
@@ -1437,7 +1500,7 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
|
|
|
data.rssi = 0x00;
|
|
|
data.ssp_mode = 0x00;
|
|
|
hci_inquiry_cache_update(hdev, &data);
|
|
|
- mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
|
|
|
+ mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
|
|
|
info->dev_class, 0, NULL);
|
|
|
}
|
|
|
|
|
@@ -1472,7 +1535,8 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
|
|
|
conn->state = BT_CONFIG;
|
|
|
hci_conn_hold(conn);
|
|
|
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
|
|
- mgmt_connected(hdev, &ev->bdaddr, conn->type);
|
|
|
+ mgmt_connected(hdev, &ev->bdaddr, conn->type,
|
|
|
+ conn->dst_type);
|
|
|
} else
|
|
|
conn->state = BT_CONNECTED;
|
|
|
|
|
@@ -1494,7 +1558,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
|
|
|
}
|
|
|
|
|
|
/* Set packet type for incoming connection */
|
|
|
- if (!conn->out && hdev->hci_ver < 3) {
|
|
|
+ if (!conn->out && hdev->hci_ver < BLUETOOTH_VER_2_0) {
|
|
|
struct hci_cp_change_conn_ptype cp;
|
|
|
cp.handle = ev->handle;
|
|
|
cp.pkt_type = cpu_to_le16(conn->pkt_type);
|
|
@@ -1505,7 +1569,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
|
|
|
conn->state = BT_CLOSED;
|
|
|
if (conn->type == ACL_LINK)
|
|
|
mgmt_connect_failed(hdev, &ev->bdaddr, conn->type,
|
|
|
- ev->status);
|
|
|
+ conn->dst_type, ev->status);
|
|
|
}
|
|
|
|
|
|
if (conn->type == ACL_LINK)
|
|
@@ -1604,26 +1668,27 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
|
|
|
|
|
|
BT_DBG("%s status %d", hdev->name, ev->status);
|
|
|
|
|
|
- if (ev->status) {
|
|
|
- hci_dev_lock(hdev);
|
|
|
- mgmt_disconnect_failed(hdev);
|
|
|
- hci_dev_unlock(hdev);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
hci_dev_lock(hdev);
|
|
|
|
|
|
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
|
|
|
if (!conn)
|
|
|
goto unlock;
|
|
|
|
|
|
- conn->state = BT_CLOSED;
|
|
|
+ if (ev->status == 0)
|
|
|
+ conn->state = BT_CLOSED;
|
|
|
|
|
|
- if (conn->type == ACL_LINK || conn->type == LE_LINK)
|
|
|
- mgmt_disconnected(hdev, &conn->dst, conn->type);
|
|
|
+ if (conn->type == ACL_LINK || conn->type == LE_LINK) {
|
|
|
+ if (ev->status != 0)
|
|
|
+ mgmt_disconnect_failed(hdev, &conn->dst, ev->status);
|
|
|
+ else
|
|
|
+ mgmt_disconnected(hdev, &conn->dst, conn->type,
|
|
|
+ conn->dst_type);
|
|
|
+ }
|
|
|
|
|
|
- hci_proto_disconn_cfm(conn, ev->reason);
|
|
|
- hci_conn_del(conn);
|
|
|
+ if (ev->status == 0) {
|
|
|
+ hci_proto_disconn_cfm(conn, ev->reason);
|
|
|
+ hci_conn_del(conn);
|
|
|
+ }
|
|
|
|
|
|
unlock:
|
|
|
hci_dev_unlock(hdev);
|
|
@@ -1961,6 +2026,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
|
|
|
hci_cc_write_ca_timeout(hdev, skb);
|
|
|
break;
|
|
|
|
|
|
+ case HCI_OP_READ_FLOW_CONTROL_MODE:
|
|
|
+ hci_cc_read_flow_control_mode(hdev, skb);
|
|
|
+ break;
|
|
|
+
|
|
|
case HCI_OP_READ_LOCAL_AMP_INFO:
|
|
|
hci_cc_read_local_amp_info(hdev, skb);
|
|
|
break;
|
|
@@ -2009,6 +2078,17 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
|
|
|
hci_cc_user_confirm_neg_reply(hdev, skb);
|
|
|
break;
|
|
|
|
|
|
+ case HCI_OP_USER_PASSKEY_REPLY:
|
|
|
+ hci_cc_user_passkey_reply(hdev, skb);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case HCI_OP_USER_PASSKEY_NEG_REPLY:
|
|
|
+ hci_cc_user_passkey_neg_reply(hdev, skb);
|
|
|
+
|
|
|
+ case HCI_OP_LE_SET_SCAN_PARAM:
|
|
|
+ hci_cc_le_set_scan_param(hdev, skb);
|
|
|
+ break;
|
|
|
+
|
|
|
case HCI_OP_LE_SET_SCAN_ENABLE:
|
|
|
hci_cc_le_set_scan_enable(hdev, skb);
|
|
|
break;
|
|
@@ -2096,7 +2176,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|
|
|
|
|
case HCI_OP_DISCONNECT:
|
|
|
if (ev->status != 0)
|
|
|
- mgmt_disconnect_failed(hdev);
|
|
|
+ mgmt_disconnect_failed(hdev, NULL, ev->status);
|
|
|
break;
|
|
|
|
|
|
case HCI_OP_LE_CREATE_CONN:
|
|
@@ -2444,7 +2524,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
|
|
|
data.rssi = info->rssi;
|
|
|
data.ssp_mode = 0x00;
|
|
|
hci_inquiry_cache_update(hdev, &data);
|
|
|
- mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
|
|
|
+ mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
|
|
|
info->dev_class, info->rssi,
|
|
|
NULL);
|
|
|
}
|
|
@@ -2461,7 +2541,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
|
|
|
data.rssi = info->rssi;
|
|
|
data.ssp_mode = 0x00;
|
|
|
hci_inquiry_cache_update(hdev, &data);
|
|
|
- mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
|
|
|
+ mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
|
|
|
info->dev_class, info->rssi,
|
|
|
NULL);
|
|
|
}
|
|
@@ -2604,7 +2684,7 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
|
|
|
data.rssi = info->rssi;
|
|
|
data.ssp_mode = 0x01;
|
|
|
hci_inquiry_cache_update(hdev, &data);
|
|
|
- mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
|
|
|
+ mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
|
|
|
info->dev_class, info->rssi, info->data);
|
|
|
}
|
|
|
|
|
@@ -2768,6 +2848,21 @@ unlock:
|
|
|
hci_dev_unlock(hdev);
|
|
|
}
|
|
|
|
|
|
+static inline void hci_user_passkey_request_evt(struct hci_dev *hdev,
|
|
|
+ struct sk_buff *skb)
|
|
|
+{
|
|
|
+ struct hci_ev_user_passkey_req *ev = (void *) skb->data;
|
|
|
+
|
|
|
+ BT_DBG("%s", hdev->name);
|
|
|
+
|
|
|
+ hci_dev_lock(hdev);
|
|
|
+
|
|
|
+ if (test_bit(HCI_MGMT, &hdev->flags))
|
|
|
+ mgmt_user_passkey_request(hdev, &ev->bdaddr);
|
|
|
+
|
|
|
+ hci_dev_unlock(hdev);
|
|
|
+}
|
|
|
+
|
|
|
static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|
|
{
|
|
|
struct hci_ev_simple_pair_complete *ev = (void *) skb->data;
|
|
@@ -2868,14 +2963,15 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
|
|
|
}
|
|
|
|
|
|
if (ev->status) {
|
|
|
- mgmt_connect_failed(hdev, &ev->bdaddr, conn->type, ev->status);
|
|
|
+ mgmt_connect_failed(hdev, &ev->bdaddr, conn->type,
|
|
|
+ conn->dst_type, ev->status);
|
|
|
hci_proto_connect_cfm(conn, ev->status);
|
|
|
conn->state = BT_CLOSED;
|
|
|
hci_conn_del(conn);
|
|
|
goto unlock;
|
|
|
}
|
|
|
|
|
|
- mgmt_connected(hdev, &ev->bdaddr, conn->type);
|
|
|
+ mgmt_connected(hdev, &ev->bdaddr, conn->type, conn->dst_type);
|
|
|
|
|
|
conn->sec_level = BT_SECURITY_LOW;
|
|
|
conn->handle = __le16_to_cpu(ev->handle);
|
|
@@ -3106,6 +3202,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
|
|
hci_user_confirm_request_evt(hdev, skb);
|
|
|
break;
|
|
|
|
|
|
+ case HCI_EV_USER_PASSKEY_REQUEST:
|
|
|
+ hci_user_passkey_request_evt(hdev, skb);
|
|
|
+ break;
|
|
|
+
|
|
|
case HCI_EV_SIMPLE_PAIR_COMPLETE:
|
|
|
hci_simple_pair_complete_evt(hdev, skb);
|
|
|
break;
|