Import of kernel-5.14.0-611.11.1.el9_7

This commit is contained in:
almalinux-bot-kernel 2025-12-05 04:11:05 +00:00
parent d18cc6d0be
commit 1e764b8f70
21 changed files with 418 additions and 184 deletions

View File

@ -12,7 +12,7 @@ RHEL_MINOR = 7
# #
# Use this spot to avoid future merge conflicts. # Use this spot to avoid future merge conflicts.
# Do not trim this comment. # Do not trim this comment.
RHEL_RELEASE = 611.9.1 RHEL_RELEASE = 611.11.1
# #
# ZSTREAM # ZSTREAM

View File

@ -542,7 +542,8 @@ enum {
#define pasid_supported(iommu) (sm_supported(iommu) && \ #define pasid_supported(iommu) (sm_supported(iommu) && \
ecap_pasid((iommu)->ecap)) ecap_pasid((iommu)->ecap))
#define ssads_supported(iommu) (sm_supported(iommu) && \ #define ssads_supported(iommu) (sm_supported(iommu) && \
ecap_slads((iommu)->ecap)) ecap_slads((iommu)->ecap) && \
ecap_smpwc(iommu->ecap))
#define nested_supported(iommu) (sm_supported(iommu) && \ #define nested_supported(iommu) (sm_supported(iommu) && \
ecap_nest((iommu)->ecap)) ecap_nest((iommu)->ecap))

View File

@ -549,12 +549,12 @@ static int e1000_set_eeprom(struct net_device *netdev,
{ {
struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw; struct e1000_hw *hw = &adapter->hw;
size_t total_len, max_len;
u16 *eeprom_buff; u16 *eeprom_buff;
void *ptr; int ret_val = 0;
int max_len;
int first_word; int first_word;
int last_word; int last_word;
int ret_val = 0; void *ptr;
u16 i; u16 i;
if (eeprom->len == 0) if (eeprom->len == 0)
@ -569,6 +569,10 @@ static int e1000_set_eeprom(struct net_device *netdev,
max_len = hw->nvm.word_size * 2; max_len = hw->nvm.word_size * 2;
if (check_add_overflow(eeprom->offset, eeprom->len, &total_len) ||
total_len > max_len)
return -EFBIG;
first_word = eeprom->offset >> 1; first_word = eeprom->offset >> 1;
last_word = (eeprom->offset + eeprom->len - 1) >> 1; last_word = (eeprom->offset + eeprom->len - 1) >> 1;
eeprom_buff = kmalloc(max_len, GFP_KERNEL); eeprom_buff = kmalloc(max_len, GFP_KERNEL);

View File

@ -98,19 +98,21 @@ struct ice_adapter *ice_adapter_get(struct pci_dev *pdev)
index = ice_adapter_xa_index(pdev); index = ice_adapter_xa_index(pdev);
scoped_guard(mutex, &ice_adapters_mutex) { scoped_guard(mutex, &ice_adapters_mutex) {
err = xa_insert(&ice_adapters, index, NULL, GFP_KERNEL);
if (err == -EBUSY) {
adapter = xa_load(&ice_adapters, index); adapter = xa_load(&ice_adapters, index);
if (adapter) {
refcount_inc(&adapter->refcount); refcount_inc(&adapter->refcount);
WARN_ON_ONCE(adapter->index != ice_adapter_index(pdev)); WARN_ON_ONCE(adapter->index != ice_adapter_index(pdev));
return adapter; return adapter;
} }
err = xa_reserve(&ice_adapters, index, GFP_KERNEL);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
adapter = ice_adapter_new(pdev); adapter = ice_adapter_new(pdev);
if (!adapter) if (!adapter) {
xa_release(&ice_adapters, index);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
}
xa_store(&ice_adapters, index, adapter, GFP_KERNEL); xa_store(&ice_adapters, index, adapter, GFP_KERNEL);
} }
return adapter; return adapter;

View File

@ -1677,6 +1677,10 @@ void mt76_wcid_cleanup(struct mt76_dev *dev, struct mt76_wcid *wcid)
skb_queue_splice_tail_init(&wcid->tx_pending, &list); skb_queue_splice_tail_init(&wcid->tx_pending, &list);
spin_unlock(&wcid->tx_pending.lock); spin_unlock(&wcid->tx_pending.lock);
spin_lock(&wcid->tx_offchannel.lock);
skb_queue_splice_tail_init(&wcid->tx_offchannel, &list);
spin_unlock(&wcid->tx_offchannel.lock);
spin_unlock_bh(&phy->tx_lock); spin_unlock_bh(&phy->tx_lock);
while ((skb = __skb_dequeue(&list)) != NULL) { while ((skb = __skb_dequeue(&list)) != NULL) {
@ -1688,7 +1692,7 @@ EXPORT_SYMBOL_GPL(mt76_wcid_cleanup);
void mt76_wcid_add_poll(struct mt76_dev *dev, struct mt76_wcid *wcid) void mt76_wcid_add_poll(struct mt76_dev *dev, struct mt76_wcid *wcid)
{ {
if (test_bit(MT76_MCU_RESET, &dev->phy.state)) if (test_bit(MT76_MCU_RESET, &dev->phy.state) || !wcid->sta)
return; return;
spin_lock_bh(&dev->sta_poll_lock); spin_lock_bh(&dev->sta_poll_lock);

View File

@ -645,6 +645,7 @@ mt76_txq_schedule_pending_wcid(struct mt76_phy *phy, struct mt76_wcid *wcid,
static void mt76_txq_schedule_pending(struct mt76_phy *phy) static void mt76_txq_schedule_pending(struct mt76_phy *phy)
{ {
LIST_HEAD(tx_list); LIST_HEAD(tx_list);
int ret = 0;
if (list_empty(&phy->tx_list)) if (list_empty(&phy->tx_list))
return; return;
@ -656,12 +657,12 @@ static void mt76_txq_schedule_pending(struct mt76_phy *phy)
list_splice_init(&phy->tx_list, &tx_list); list_splice_init(&phy->tx_list, &tx_list);
while (!list_empty(&tx_list)) { while (!list_empty(&tx_list)) {
struct mt76_wcid *wcid; struct mt76_wcid *wcid;
int ret;
wcid = list_first_entry(&tx_list, struct mt76_wcid, tx_list); wcid = list_first_entry(&tx_list, struct mt76_wcid, tx_list);
list_del_init(&wcid->tx_list); list_del_init(&wcid->tx_list);
spin_unlock(&phy->tx_lock); spin_unlock(&phy->tx_lock);
if (ret >= 0)
ret = mt76_txq_schedule_pending_wcid(phy, wcid, &wcid->tx_offchannel); ret = mt76_txq_schedule_pending_wcid(phy, wcid, &wcid->tx_offchannel);
if (ret >= 0 && !phy->offchannel) if (ret >= 0 && !phy->offchannel)
ret = mt76_txq_schedule_pending_wcid(phy, wcid, &wcid->tx_pending); ret = mt76_txq_schedule_pending_wcid(phy, wcid, &wcid->tx_pending);
@ -671,9 +672,6 @@ static void mt76_txq_schedule_pending(struct mt76_phy *phy)
!skb_queue_empty(&wcid->tx_offchannel) && !skb_queue_empty(&wcid->tx_offchannel) &&
list_empty(&wcid->tx_list)) list_empty(&wcid->tx_list))
list_add_tail(&wcid->tx_list, &phy->tx_list); list_add_tail(&wcid->tx_list, &phy->tx_list);
if (ret < 0)
break;
} }
spin_unlock(&phy->tx_lock); spin_unlock(&phy->tx_lock);

View File

@ -167,7 +167,7 @@ static int tpmi_get_logical_id(unsigned int cpu, struct tpmi_cpu_info *info)
info->punit_thread_id = FIELD_GET(LP_ID_MASK, data); info->punit_thread_id = FIELD_GET(LP_ID_MASK, data);
info->punit_core_id = FIELD_GET(MODULE_ID_MASK, data); info->punit_core_id = FIELD_GET(MODULE_ID_MASK, data);
info->pkg_id = topology_physical_package_id(cpu); info->pkg_id = topology_logical_package_id(cpu);
info->linux_cpu = cpu; info->linux_cpu = cpu;
return 0; return 0;

View File

@ -4543,10 +4543,16 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
} }
status = nfs_ok; status = nfs_ok;
if (conf) { if (conf) {
if (get_client_locked(conf) == nfs_ok) {
old = unconf; old = unconf;
unhash_client_locked(old); unhash_client_locked(old);
nfsd4_change_callback(conf, &unconf->cl_cb_conn); nfsd4_change_callback(conf, &unconf->cl_cb_conn);
} else { } else {
conf = NULL;
}
}
if (!conf) {
old = find_confirmed_client_by_name(&unconf->cl_name, nn); old = find_confirmed_client_by_name(&unconf->cl_name, nn);
if (old) { if (old) {
status = nfserr_clid_inuse; status = nfserr_clid_inuse;
@ -4563,10 +4569,14 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
} }
trace_nfsd_clid_replaced(&old->cl_clientid); trace_nfsd_clid_replaced(&old->cl_clientid);
} }
status = get_client_locked(unconf);
if (status != nfs_ok) {
old = NULL;
goto out;
}
move_to_confirmed(unconf); move_to_confirmed(unconf);
conf = unconf; conf = unconf;
} }
get_client_locked(conf);
spin_unlock(&nn->client_lock); spin_unlock(&nn->client_lock);
if (conf == unconf) if (conf == unconf)
fsnotify_dentry(conf->cl_nfsd_info_dentry, FS_MODIFY); fsnotify_dentry(conf->cl_nfsd_info_dentry, FS_MODIFY);

View File

@ -542,6 +542,7 @@ struct hci_dev {
struct hci_conn_hash conn_hash; struct hci_conn_hash conn_hash;
struct list_head mesh_pending; struct list_head mesh_pending;
struct mutex mgmt_pending_lock;
struct list_head mgmt_pending; struct list_head mgmt_pending;
struct list_head reject_list; struct list_head reject_list;
struct list_head accept_list; struct list_head accept_list;
@ -2409,7 +2410,6 @@ void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev,
u8 instance); u8 instance);
void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev, void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
u8 instance); u8 instance);
void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle);
int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip); int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip);
void mgmt_adv_monitor_device_lost(struct hci_dev *hdev, u16 handle, void mgmt_adv_monitor_device_lost(struct hci_dev *hdev, u16 handle,
bdaddr_t *bdaddr, u8 addr_type); bdaddr_t *bdaddr, u8 addr_type);

View File

@ -93,7 +93,7 @@ int hci_update_class_sync(struct hci_dev *hdev);
int hci_update_eir_sync(struct hci_dev *hdev); int hci_update_eir_sync(struct hci_dev *hdev);
int hci_update_class_sync(struct hci_dev *hdev); int hci_update_class_sync(struct hci_dev *hdev);
int hci_update_name_sync(struct hci_dev *hdev); int hci_update_name_sync(struct hci_dev *hdev, const u8 *name);
int hci_write_ssp_mode_sync(struct hci_dev *hdev, u8 mode); int hci_write_ssp_mode_sync(struct hci_dev *hdev, u8 mode);
int hci_get_random_address(struct hci_dev *hdev, bool require_privacy, int hci_get_random_address(struct hci_dev *hdev, bool require_privacy,

View File

@ -848,7 +848,7 @@ struct mgmt_cp_set_mesh {
__le16 window; __le16 window;
__le16 period; __le16 period;
__u8 num_ad_types; __u8 num_ad_types;
__u8 ad_types[]; __u8 ad_types[] __counted_by(num_ad_types);
} __packed; } __packed;
#define MGMT_SET_MESH_RECEIVER_SIZE 6 #define MGMT_SET_MESH_RECEIVER_SIZE 6

View File

@ -1895,10 +1895,8 @@ void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor)
if (monitor->handle) if (monitor->handle)
idr_remove(&hdev->adv_monitors_idr, monitor->handle); idr_remove(&hdev->adv_monitors_idr, monitor->handle);
if (monitor->state != ADV_MONITOR_STATE_NOT_REGISTERED) { if (monitor->state != ADV_MONITOR_STATE_NOT_REGISTERED)
hdev->adv_monitors_cnt--; hdev->adv_monitors_cnt--;
mgmt_adv_monitor_removed(hdev, monitor->handle);
}
kfree(monitor); kfree(monitor);
} }
@ -2510,6 +2508,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
mutex_init(&hdev->lock); mutex_init(&hdev->lock);
mutex_init(&hdev->req_lock); mutex_init(&hdev->req_lock);
mutex_init(&hdev->mgmt_pending_lock);
ida_init(&hdev->unset_handle_ida); ida_init(&hdev->unset_handle_ida);

View File

@ -3412,13 +3412,13 @@ int hci_update_scan_sync(struct hci_dev *hdev)
return hci_write_scan_enable_sync(hdev, scan); return hci_write_scan_enable_sync(hdev, scan);
} }
int hci_update_name_sync(struct hci_dev *hdev) int hci_update_name_sync(struct hci_dev *hdev, const u8 *name)
{ {
struct hci_cp_write_local_name cp; struct hci_cp_write_local_name cp;
memset(&cp, 0, sizeof(cp)); memset(&cp, 0, sizeof(cp));
memcpy(cp.name, hdev->dev_name, sizeof(cp.name)); memcpy(cp.name, name, sizeof(cp.name));
return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_LOCAL_NAME, return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_LOCAL_NAME,
sizeof(cp), &cp, sizeof(cp), &cp,
@ -3471,7 +3471,7 @@ int hci_powered_update_sync(struct hci_dev *hdev)
hci_write_fast_connectable_sync(hdev, false); hci_write_fast_connectable_sync(hdev, false);
hci_update_scan_sync(hdev); hci_update_scan_sync(hdev);
hci_update_class_sync(hdev); hci_update_class_sync(hdev);
hci_update_name_sync(hdev); hci_update_name_sync(hdev, hdev->dev_name);
hci_update_eir_sync(hdev); hci_update_eir_sync(hdev);
} }

View File

@ -1324,8 +1324,7 @@ static void mgmt_set_powered_complete(struct hci_dev *hdev, void *data, int err)
struct mgmt_mode *cp; struct mgmt_mode *cp;
/* Make sure cmd still outstanding. */ /* Make sure cmd still outstanding. */
if (err == -ECANCELED || if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
cmd != pending_find(MGMT_OP_SET_POWERED, hdev))
return; return;
cp = cmd->param; cp = cmd->param;
@ -1352,23 +1351,29 @@ static void mgmt_set_powered_complete(struct hci_dev *hdev, void *data, int err)
mgmt_status(err)); mgmt_status(err));
} }
mgmt_pending_remove(cmd); mgmt_pending_free(cmd);
} }
static int set_powered_sync(struct hci_dev *hdev, void *data) static int set_powered_sync(struct hci_dev *hdev, void *data)
{ {
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
struct mgmt_mode *cp; struct mgmt_mode cp;
mutex_lock(&hdev->mgmt_pending_lock);
/* Make sure cmd still outstanding. */ /* Make sure cmd still outstanding. */
if (cmd != pending_find(MGMT_OP_SET_POWERED, hdev)) if (!__mgmt_pending_listed(hdev, cmd)) {
mutex_unlock(&hdev->mgmt_pending_lock);
return -ECANCELED; return -ECANCELED;
}
cp = cmd->param; memcpy(&cp, cmd->param, sizeof(cp));
mutex_unlock(&hdev->mgmt_pending_lock);
BT_DBG("%s", hdev->name); BT_DBG("%s", hdev->name);
return hci_set_powered_sync(hdev, cp->val); return hci_set_powered_sync(hdev, cp.val);
} }
static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
@ -1447,22 +1452,17 @@ static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
send_settings_rsp(cmd->sk, cmd->opcode, match->hdev); send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
list_del(&cmd->list);
if (match->sk == NULL) { if (match->sk == NULL) {
match->sk = cmd->sk; match->sk = cmd->sk;
sock_hold(match->sk); sock_hold(match->sk);
} }
mgmt_pending_free(cmd);
} }
static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data) static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
{ {
u8 *status = data; u8 *status = data;
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status); mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, *status);
mgmt_pending_remove(cmd);
} }
static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data) static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
@ -1476,8 +1476,6 @@ static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
if (cmd->cmd_complete) { if (cmd->cmd_complete) {
cmd->cmd_complete(cmd, match->mgmt_status); cmd->cmd_complete(cmd, match->mgmt_status);
mgmt_pending_remove(cmd);
return; return;
} }
@ -1486,13 +1484,13 @@ static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status) static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
{ {
return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, return mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status,
cmd->param, cmd->param_len); cmd->param, cmd->param_len);
} }
static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status) static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
{ {
return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, return mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status,
cmd->param, sizeof(struct mgmt_addr_info)); cmd->param, sizeof(struct mgmt_addr_info));
} }
@ -1524,15 +1522,14 @@ static void mgmt_set_discoverable_complete(struct hci_dev *hdev, void *data,
bt_dev_dbg(hdev, "err %d", err); bt_dev_dbg(hdev, "err %d", err);
/* Make sure cmd still outstanding. */ /* Make sure cmd still outstanding. */
if (err == -ECANCELED || if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
cmd != pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
return; return;
hci_dev_lock(hdev); hci_dev_lock(hdev);
if (err) { if (err) {
u8 mgmt_err = mgmt_status(err); u8 mgmt_err = mgmt_status(err);
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err); mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE); hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
goto done; goto done;
} }
@ -1547,12 +1544,15 @@ static void mgmt_set_discoverable_complete(struct hci_dev *hdev, void *data,
new_settings(hdev, cmd->sk); new_settings(hdev, cmd->sk);
done: done:
mgmt_pending_remove(cmd); mgmt_pending_free(cmd);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
static int set_discoverable_sync(struct hci_dev *hdev, void *data) static int set_discoverable_sync(struct hci_dev *hdev, void *data)
{ {
if (!mgmt_pending_listed(hdev, data))
return -ECANCELED;
BT_DBG("%s", hdev->name); BT_DBG("%s", hdev->name);
return hci_update_discoverable_sync(hdev); return hci_update_discoverable_sync(hdev);
@ -1699,15 +1699,14 @@ static void mgmt_set_connectable_complete(struct hci_dev *hdev, void *data,
bt_dev_dbg(hdev, "err %d", err); bt_dev_dbg(hdev, "err %d", err);
/* Make sure cmd still outstanding. */ /* Make sure cmd still outstanding. */
if (err == -ECANCELED || if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
cmd != pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
return; return;
hci_dev_lock(hdev); hci_dev_lock(hdev);
if (err) { if (err) {
u8 mgmt_err = mgmt_status(err); u8 mgmt_err = mgmt_status(err);
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err); mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
goto done; goto done;
} }
@ -1715,7 +1714,7 @@ static void mgmt_set_connectable_complete(struct hci_dev *hdev, void *data,
new_settings(hdev, cmd->sk); new_settings(hdev, cmd->sk);
done: done:
mgmt_pending_remove(cmd); mgmt_pending_free(cmd);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
@ -1751,6 +1750,9 @@ static int set_connectable_update_settings(struct hci_dev *hdev,
static int set_connectable_sync(struct hci_dev *hdev, void *data) static int set_connectable_sync(struct hci_dev *hdev, void *data)
{ {
if (!mgmt_pending_listed(hdev, data))
return -ECANCELED;
BT_DBG("%s", hdev->name); BT_DBG("%s", hdev->name);
return hci_update_connectable_sync(hdev); return hci_update_connectable_sync(hdev);
@ -1927,14 +1929,17 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
{ {
struct cmd_lookup match = { NULL, hdev }; struct cmd_lookup match = { NULL, hdev };
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
struct mgmt_mode *cp = cmd->param; struct mgmt_mode *cp;
u8 enable = cp->val; u8 enable;
bool changed; bool changed;
/* Make sure cmd still outstanding. */ /* Make sure cmd still outstanding. */
if (err == -ECANCELED || cmd != pending_find(MGMT_OP_SET_SSP, hdev)) if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
return; return;
cp = cmd->param;
enable = cp->val;
if (err) { if (err) {
u8 mgmt_err = mgmt_status(err); u8 mgmt_err = mgmt_status(err);
@ -1943,8 +1948,7 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
new_settings(hdev, NULL); new_settings(hdev, NULL);
} }
mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp, mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
&mgmt_err);
return; return;
} }
@ -1954,7 +1958,7 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED); changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
} }
mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match); settings_rsp(cmd, &match);
if (changed) if (changed)
new_settings(hdev, match.sk); new_settings(hdev, match.sk);
@ -1968,14 +1972,25 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
static int set_ssp_sync(struct hci_dev *hdev, void *data) static int set_ssp_sync(struct hci_dev *hdev, void *data)
{ {
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
struct mgmt_mode *cp = cmd->param; struct mgmt_mode cp;
bool changed = false; bool changed = false;
int err; int err;
if (cp->val) mutex_lock(&hdev->mgmt_pending_lock);
if (!__mgmt_pending_listed(hdev, cmd)) {
mutex_unlock(&hdev->mgmt_pending_lock);
return -ECANCELED;
}
memcpy(&cp, cmd->param, sizeof(cp));
mutex_unlock(&hdev->mgmt_pending_lock);
if (cp.val)
changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED); changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
err = hci_write_ssp_mode_sync(hdev, cp->val); err = hci_write_ssp_mode_sync(hdev, cp.val);
if (!err && changed) if (!err && changed)
hci_dev_clear_flag(hdev, HCI_SSP_ENABLED); hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
@ -2068,32 +2083,50 @@ static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
static void set_le_complete(struct hci_dev *hdev, void *data, int err) static void set_le_complete(struct hci_dev *hdev, void *data, int err)
{ {
struct mgmt_pending_cmd *cmd = data;
struct cmd_lookup match = { NULL, hdev }; struct cmd_lookup match = { NULL, hdev };
u8 status = mgmt_status(err); u8 status = mgmt_status(err);
bt_dev_dbg(hdev, "err %d", err); bt_dev_dbg(hdev, "err %d", err);
if (status) { if (err == -ECANCELED || !mgmt_pending_valid(hdev, data))
mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
&status);
return; return;
if (status) {
mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, status);
goto done;
} }
mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match); settings_rsp(cmd, &match);
new_settings(hdev, match.sk); new_settings(hdev, match.sk);
if (match.sk) if (match.sk)
sock_put(match.sk); sock_put(match.sk);
done:
mgmt_pending_free(cmd);
} }
static int set_le_sync(struct hci_dev *hdev, void *data) static int set_le_sync(struct hci_dev *hdev, void *data)
{ {
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
struct mgmt_mode *cp = cmd->param; struct mgmt_mode cp;
u8 val = !!cp->val; u8 val;
int err; int err;
mutex_lock(&hdev->mgmt_pending_lock);
if (!__mgmt_pending_listed(hdev, cmd)) {
mutex_unlock(&hdev->mgmt_pending_lock);
return -ECANCELED;
}
memcpy(&cp, cmd->param, sizeof(cp));
val = !!cp.val;
mutex_unlock(&hdev->mgmt_pending_lock);
if (!val) { if (!val) {
hci_clear_adv_instance_sync(hdev, NULL, 0x00, true); hci_clear_adv_instance_sync(hdev, NULL, 0x00, true);
@ -2135,23 +2168,45 @@ static void set_mesh_complete(struct hci_dev *hdev, void *data, int err)
{ {
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
u8 status = mgmt_status(err); u8 status = mgmt_status(err);
struct sock *sk = cmd->sk; struct sock *sk;
if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
return;
sk = cmd->sk;
if (status) { if (status) {
mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev, mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER,
status);
mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev, true,
cmd_status_rsp, &status); cmd_status_rsp, &status);
return; goto done;
} }
mgmt_pending_remove(cmd);
mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER, 0, NULL, 0); mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER, 0, NULL, 0);
done:
mgmt_pending_free(cmd);
} }
static int set_mesh_sync(struct hci_dev *hdev, void *data) static int set_mesh_sync(struct hci_dev *hdev, void *data)
{ {
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
struct mgmt_cp_set_mesh *cp = cmd->param; DEFINE_FLEX(struct mgmt_cp_set_mesh, cp, ad_types, num_ad_types,
size_t len = cmd->param_len; sizeof(hdev->mesh_ad_types));
size_t len;
mutex_lock(&hdev->mgmt_pending_lock);
if (!__mgmt_pending_listed(hdev, cmd)) {
mutex_unlock(&hdev->mgmt_pending_lock);
return -ECANCELED;
}
len = cmd->param_len;
memcpy(cp, cmd->param, min(__struct_size(cp), len));
mutex_unlock(&hdev->mgmt_pending_lock);
memset(hdev->mesh_ad_types, 0, sizeof(hdev->mesh_ad_types)); memset(hdev->mesh_ad_types, 0, sizeof(hdev->mesh_ad_types));
@ -2160,7 +2215,10 @@ static int set_mesh_sync(struct hci_dev *hdev, void *data)
else else
hci_dev_clear_flag(hdev, HCI_MESH); hci_dev_clear_flag(hdev, HCI_MESH);
len -= sizeof(*cp); hdev->le_scan_interval = __le16_to_cpu(cp->period);
hdev->le_scan_window = __le16_to_cpu(cp->window);
len -= sizeof(struct mgmt_cp_set_mesh);
/* If filters don't fit, forward all adv pkts */ /* If filters don't fit, forward all adv pkts */
if (len <= sizeof(hdev->mesh_ad_types)) if (len <= sizeof(hdev->mesh_ad_types))
@ -2174,6 +2232,7 @@ static int set_mesh(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
{ {
struct mgmt_cp_set_mesh *cp = data; struct mgmt_cp_set_mesh *cp = data;
struct mgmt_pending_cmd *cmd; struct mgmt_pending_cmd *cmd;
__u16 period, window;
int err = 0; int err = 0;
bt_dev_dbg(hdev, "sock %p", sk); bt_dev_dbg(hdev, "sock %p", sk);
@ -2187,6 +2246,23 @@ static int set_mesh(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER, return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER,
MGMT_STATUS_INVALID_PARAMS); MGMT_STATUS_INVALID_PARAMS);
/* Keep allowed ranges in sync with set_scan_params() */
period = __le16_to_cpu(cp->period);
if (period < 0x0004 || period > 0x4000)
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER,
MGMT_STATUS_INVALID_PARAMS);
window = __le16_to_cpu(cp->window);
if (window < 0x0004 || window > 0x4000)
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER,
MGMT_STATUS_INVALID_PARAMS);
if (window > period)
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER,
MGMT_STATUS_INVALID_PARAMS);
hci_dev_lock(hdev); hci_dev_lock(hdev);
cmd = mgmt_pending_add(sk, MGMT_OP_SET_MESH_RECEIVER, hdev, data, len); cmd = mgmt_pending_add(sk, MGMT_OP_SET_MESH_RECEIVER, hdev, data, len);
@ -2637,7 +2713,7 @@ static void mgmt_class_complete(struct hci_dev *hdev, void *data, int err)
bt_dev_dbg(hdev, "err %d", err); bt_dev_dbg(hdev, "err %d", err);
mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
mgmt_status(err), hdev->dev_class, 3); mgmt_status(err), hdev->dev_class, 3);
mgmt_pending_free(cmd); mgmt_pending_free(cmd);
@ -3425,7 +3501,7 @@ static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
bacpy(&rp.addr.bdaddr, &conn->dst); bacpy(&rp.addr.bdaddr, &conn->dst);
rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type); rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, err = mgmt_cmd_complete(cmd->sk, cmd->hdev->id, MGMT_OP_PAIR_DEVICE,
status, &rp, sizeof(rp)); status, &rp, sizeof(rp));
/* So we don't get further callbacks for this connection */ /* So we don't get further callbacks for this connection */
@ -3851,15 +3927,16 @@ static int name_changed_sync(struct hci_dev *hdev, void *data)
static void set_name_complete(struct hci_dev *hdev, void *data, int err) static void set_name_complete(struct hci_dev *hdev, void *data, int err)
{ {
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
struct mgmt_cp_set_local_name *cp = cmd->param; struct mgmt_cp_set_local_name *cp;
u8 status = mgmt_status(err); u8 status = mgmt_status(err);
bt_dev_dbg(hdev, "err %d", err); bt_dev_dbg(hdev, "err %d", err);
if (err == -ECANCELED || if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
cmd != pending_find(MGMT_OP_SET_LOCAL_NAME, hdev))
return; return;
cp = cmd->param;
if (status) { if (status) {
mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
status); status);
@ -3871,13 +3948,27 @@ static void set_name_complete(struct hci_dev *hdev, void *data, int err)
hci_cmd_sync_queue(hdev, name_changed_sync, NULL, NULL); hci_cmd_sync_queue(hdev, name_changed_sync, NULL, NULL);
} }
mgmt_pending_remove(cmd); mgmt_pending_free(cmd);
} }
static int set_name_sync(struct hci_dev *hdev, void *data) static int set_name_sync(struct hci_dev *hdev, void *data)
{ {
struct mgmt_pending_cmd *cmd = data;
struct mgmt_cp_set_local_name cp;
mutex_lock(&hdev->mgmt_pending_lock);
if (!__mgmt_pending_listed(hdev, cmd)) {
mutex_unlock(&hdev->mgmt_pending_lock);
return -ECANCELED;
}
memcpy(&cp, cmd->param, sizeof(cp));
mutex_unlock(&hdev->mgmt_pending_lock);
if (lmp_bredr_capable(hdev)) { if (lmp_bredr_capable(hdev)) {
hci_update_name_sync(hdev); hci_update_name_sync(hdev, cp.name);
hci_update_eir_sync(hdev); hci_update_eir_sync(hdev);
} }
@ -4029,12 +4120,10 @@ int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip)
static void set_default_phy_complete(struct hci_dev *hdev, void *data, int err) static void set_default_phy_complete(struct hci_dev *hdev, void *data, int err)
{ {
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
struct sk_buff *skb = cmd->skb; struct sk_buff *skb;
u8 status = mgmt_status(err); u8 status = mgmt_status(err);
if (err == -ECANCELED || skb = cmd->skb;
cmd != pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev))
return;
if (!status) { if (!status) {
if (!skb) if (!skb)
@ -4061,7 +4150,7 @@ static void set_default_phy_complete(struct hci_dev *hdev, void *data, int err)
if (skb && !IS_ERR(skb)) if (skb && !IS_ERR(skb))
kfree_skb(skb); kfree_skb(skb);
mgmt_pending_remove(cmd); mgmt_pending_free(cmd);
} }
static int set_default_phy_sync(struct hci_dev *hdev, void *data) static int set_default_phy_sync(struct hci_dev *hdev, void *data)
@ -4069,7 +4158,9 @@ static int set_default_phy_sync(struct hci_dev *hdev, void *data)
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
struct mgmt_cp_set_phy_configuration *cp = cmd->param; struct mgmt_cp_set_phy_configuration *cp = cmd->param;
struct hci_cp_le_set_default_phy cp_phy; struct hci_cp_le_set_default_phy cp_phy;
u32 selected_phys = __le32_to_cpu(cp->selected_phys); u32 selected_phys;
selected_phys = __le32_to_cpu(cp->selected_phys);
memset(&cp_phy, 0, sizeof(cp_phy)); memset(&cp_phy, 0, sizeof(cp_phy));
@ -4209,7 +4300,7 @@ static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
goto unlock; goto unlock;
} }
cmd = mgmt_pending_add(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data, cmd = mgmt_pending_new(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,
len); len);
if (!cmd) if (!cmd)
err = -ENOMEM; err = -ENOMEM;
@ -5106,24 +5197,14 @@ static void mgmt_adv_monitor_added(struct sock *sk, struct hci_dev *hdev,
mgmt_event(MGMT_EV_ADV_MONITOR_ADDED, hdev, &ev, sizeof(ev), sk); mgmt_event(MGMT_EV_ADV_MONITOR_ADDED, hdev, &ev, sizeof(ev), sk);
} }
void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle) static void mgmt_adv_monitor_removed(struct sock *sk, struct hci_dev *hdev,
__le16 handle)
{ {
struct mgmt_ev_adv_monitor_removed ev; struct mgmt_ev_adv_monitor_removed ev;
struct mgmt_pending_cmd *cmd;
struct sock *sk_skip = NULL;
struct mgmt_cp_remove_adv_monitor *cp;
cmd = pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev); ev.monitor_handle = handle;
if (cmd) {
cp = cmd->param;
if (cp->monitor_handle) mgmt_event(MGMT_EV_ADV_MONITOR_REMOVED, hdev, &ev, sizeof(ev), sk);
sk_skip = cmd->sk;
}
ev.monitor_handle = cpu_to_le16(handle);
mgmt_event(MGMT_EV_ADV_MONITOR_REMOVED, hdev, &ev, sizeof(ev), sk_skip);
} }
static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev, static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev,
@ -5180,7 +5261,17 @@ static void mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev,
{ {
struct mgmt_rp_add_adv_patterns_monitor rp; struct mgmt_rp_add_adv_patterns_monitor rp;
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
struct adv_monitor *monitor = cmd->user_data; struct adv_monitor *monitor;
/* This is likely the result of hdev being closed and mgmt_index_removed
* is attempting to clean up any pending command so
* hci_adv_monitors_clear is about to be called which will take care of
* freeing the adv_monitor instances.
*/
if (status == -ECANCELED && !mgmt_pending_valid(hdev, cmd))
return;
monitor = cmd->user_data;
hci_dev_lock(hdev); hci_dev_lock(hdev);
@ -5194,7 +5285,7 @@ static void mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev,
hci_update_passive_scan(hdev); hci_update_passive_scan(hdev);
} }
mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
mgmt_status(status), &rp, sizeof(rp)); mgmt_status(status), &rp, sizeof(rp));
mgmt_pending_remove(cmd); mgmt_pending_remove(cmd);
@ -5206,9 +5297,20 @@ static void mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev,
static int mgmt_add_adv_patterns_monitor_sync(struct hci_dev *hdev, void *data) static int mgmt_add_adv_patterns_monitor_sync(struct hci_dev *hdev, void *data)
{ {
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
struct adv_monitor *monitor = cmd->user_data; struct adv_monitor *mon;
return hci_add_adv_monitor(hdev, monitor); mutex_lock(&hdev->mgmt_pending_lock);
if (!__mgmt_pending_listed(hdev, cmd)) {
mutex_unlock(&hdev->mgmt_pending_lock);
return -ECANCELED;
}
mon = cmd->user_data;
mutex_unlock(&hdev->mgmt_pending_lock);
return hci_add_adv_monitor(hdev, mon);
} }
static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev, static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
@ -5225,8 +5327,7 @@ static int __add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
if (pending_find(MGMT_OP_SET_LE, hdev) || if (pending_find(MGMT_OP_SET_LE, hdev) ||
pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) || pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) ||
pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev) || pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev)) {
pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev)) {
status = MGMT_STATUS_BUSY; status = MGMT_STATUS_BUSY;
goto unlock; goto unlock;
} }
@ -5396,8 +5497,7 @@ static void mgmt_remove_adv_monitor_complete(struct hci_dev *hdev,
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
struct mgmt_cp_remove_adv_monitor *cp; struct mgmt_cp_remove_adv_monitor *cp;
if (status == -ECANCELED || if (status == -ECANCELED)
cmd != pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev))
return; return;
hci_dev_lock(hdev); hci_dev_lock(hdev);
@ -5406,12 +5506,14 @@ static void mgmt_remove_adv_monitor_complete(struct hci_dev *hdev,
rp.monitor_handle = cp->monitor_handle; rp.monitor_handle = cp->monitor_handle;
if (!status) if (!status) {
mgmt_adv_monitor_removed(cmd->sk, hdev, cp->monitor_handle);
hci_update_passive_scan(hdev); hci_update_passive_scan(hdev);
}
mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
mgmt_status(status), &rp, sizeof(rp)); mgmt_status(status), &rp, sizeof(rp));
mgmt_pending_remove(cmd); mgmt_pending_free(cmd);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
bt_dev_dbg(hdev, "remove monitor %d complete, status %d", bt_dev_dbg(hdev, "remove monitor %d complete, status %d",
@ -5421,10 +5523,6 @@ static void mgmt_remove_adv_monitor_complete(struct hci_dev *hdev,
static int mgmt_remove_adv_monitor_sync(struct hci_dev *hdev, void *data) static int mgmt_remove_adv_monitor_sync(struct hci_dev *hdev, void *data)
{ {
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
if (cmd != pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev))
return -ECANCELED;
struct mgmt_cp_remove_adv_monitor *cp = cmd->param; struct mgmt_cp_remove_adv_monitor *cp = cmd->param;
u16 handle = __le16_to_cpu(cp->monitor_handle); u16 handle = __le16_to_cpu(cp->monitor_handle);
@ -5443,14 +5541,13 @@ static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev,
hci_dev_lock(hdev); hci_dev_lock(hdev);
if (pending_find(MGMT_OP_SET_LE, hdev) || if (pending_find(MGMT_OP_SET_LE, hdev) ||
pending_find(MGMT_OP_REMOVE_ADV_MONITOR, hdev) ||
pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) || pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR, hdev) ||
pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev)) { pending_find(MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, hdev)) {
status = MGMT_STATUS_BUSY; status = MGMT_STATUS_BUSY;
goto unlock; goto unlock;
} }
cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADV_MONITOR, hdev, data, len); cmd = mgmt_pending_new(sk, MGMT_OP_REMOVE_ADV_MONITOR, hdev, data, len);
if (!cmd) { if (!cmd) {
status = MGMT_STATUS_NO_RESOURCES; status = MGMT_STATUS_NO_RESOURCES;
goto unlock; goto unlock;
@ -5460,7 +5557,7 @@ static int remove_adv_monitor(struct sock *sk, struct hci_dev *hdev,
mgmt_remove_adv_monitor_complete); mgmt_remove_adv_monitor_complete);
if (err) { if (err) {
mgmt_pending_remove(cmd); mgmt_pending_free(cmd);
if (err == -ENOMEM) if (err == -ENOMEM)
status = MGMT_STATUS_NO_RESOURCES; status = MGMT_STATUS_NO_RESOURCES;
@ -5480,7 +5577,8 @@ unlock:
status); status);
} }
static void read_local_oob_data_complete(struct hci_dev *hdev, void *data, int err) static void read_local_oob_data_complete(struct hci_dev *hdev, void *data,
int err)
{ {
struct mgmt_rp_read_local_oob_data mgmt_rp; struct mgmt_rp_read_local_oob_data mgmt_rp;
size_t rp_size = sizeof(mgmt_rp); size_t rp_size = sizeof(mgmt_rp);
@ -5500,7 +5598,8 @@ static void read_local_oob_data_complete(struct hci_dev *hdev, void *data, int e
bt_dev_dbg(hdev, "status %d", status); bt_dev_dbg(hdev, "status %d", status);
if (status) { if (status) {
mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, status); mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
status);
goto remove; goto remove;
} }
@ -5782,17 +5881,12 @@ static void start_discovery_complete(struct hci_dev *hdev, void *data, int err)
bt_dev_dbg(hdev, "err %d", err); bt_dev_dbg(hdev, "err %d", err);
if (err == -ECANCELED) if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
return; return;
if (cmd != pending_find(MGMT_OP_START_DISCOVERY, hdev) && mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err),
cmd != pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev) &&
cmd != pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev))
return;
mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err),
cmd->param, 1); cmd->param, 1);
mgmt_pending_remove(cmd); mgmt_pending_free(cmd);
hci_discovery_set_state(hdev, err ? DISCOVERY_STOPPED: hci_discovery_set_state(hdev, err ? DISCOVERY_STOPPED:
DISCOVERY_FINDING); DISCOVERY_FINDING);
@ -5800,6 +5894,9 @@ static void start_discovery_complete(struct hci_dev *hdev, void *data, int err)
static int start_discovery_sync(struct hci_dev *hdev, void *data) static int start_discovery_sync(struct hci_dev *hdev, void *data)
{ {
if (!mgmt_pending_listed(hdev, data))
return -ECANCELED;
return hci_start_discovery_sync(hdev); return hci_start_discovery_sync(hdev);
} }
@ -6005,15 +6102,14 @@ static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err)
{ {
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
if (err == -ECANCELED || if (err == -ECANCELED || !mgmt_pending_valid(hdev, cmd))
cmd != pending_find(MGMT_OP_STOP_DISCOVERY, hdev))
return; return;
bt_dev_dbg(hdev, "err %d", err); bt_dev_dbg(hdev, "err %d", err);
mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err), mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err),
cmd->param, 1); cmd->param, 1);
mgmt_pending_remove(cmd); mgmt_pending_free(cmd);
if (!err) if (!err)
hci_discovery_set_state(hdev, DISCOVERY_STOPPED); hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
@ -6021,6 +6117,9 @@ static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err)
static int stop_discovery_sync(struct hci_dev *hdev, void *data) static int stop_discovery_sync(struct hci_dev *hdev, void *data)
{ {
if (!mgmt_pending_listed(hdev, data))
return -ECANCELED;
return hci_stop_discovery_sync(hdev); return hci_stop_discovery_sync(hdev);
} }
@ -6230,14 +6329,18 @@ static void enable_advertising_instance(struct hci_dev *hdev, int err)
static void set_advertising_complete(struct hci_dev *hdev, void *data, int err) static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
{ {
struct mgmt_pending_cmd *cmd = data;
struct cmd_lookup match = { NULL, hdev }; struct cmd_lookup match = { NULL, hdev };
u8 instance; u8 instance;
struct adv_info *adv_instance; struct adv_info *adv_instance;
u8 status = mgmt_status(err); u8 status = mgmt_status(err);
if (err == -ECANCELED || !mgmt_pending_valid(hdev, data))
return;
if (status) { if (status) {
mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, status);
cmd_status_rsp, &status); mgmt_pending_free(cmd);
return; return;
} }
@ -6246,8 +6349,7 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
else else
hci_dev_clear_flag(hdev, HCI_ADVERTISING); hci_dev_clear_flag(hdev, HCI_ADVERTISING);
mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp, settings_rsp(cmd, &match);
&match);
new_settings(hdev, match.sk); new_settings(hdev, match.sk);
@ -6279,10 +6381,23 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
static int set_adv_sync(struct hci_dev *hdev, void *data) static int set_adv_sync(struct hci_dev *hdev, void *data)
{ {
struct mgmt_pending_cmd *cmd = data; struct mgmt_pending_cmd *cmd = data;
struct mgmt_mode *cp = cmd->param; struct mgmt_mode cp;
u8 val = !!cp->val; u8 val;
if (cp->val == 0x02) mutex_lock(&hdev->mgmt_pending_lock);
if (!__mgmt_pending_listed(hdev, cmd)) {
mutex_unlock(&hdev->mgmt_pending_lock);
return -ECANCELED;
}
memcpy(&cp, cmd->param, sizeof(cp));
mutex_unlock(&hdev->mgmt_pending_lock);
val = !!cp.val;
if (cp.val == 0x02)
hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE); hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
else else
hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE); hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
@ -6452,6 +6567,7 @@ static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
MGMT_STATUS_NOT_SUPPORTED); MGMT_STATUS_NOT_SUPPORTED);
/* Keep allowed ranges in sync with set_mesh() */
interval = __le16_to_cpu(cp->interval); interval = __le16_to_cpu(cp->interval);
if (interval < 0x0004 || interval > 0x4000) if (interval < 0x0004 || interval > 0x4000)
@ -6590,7 +6706,7 @@ static void set_bredr_complete(struct hci_dev *hdev, void *data, int err)
*/ */
hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED); hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err); mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
} else { } else {
send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev); send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
new_settings(hdev, cmd->sk); new_settings(hdev, cmd->sk);
@ -6727,7 +6843,7 @@ static void set_secure_conn_complete(struct hci_dev *hdev, void *data, int err)
if (err) { if (err) {
u8 mgmt_err = mgmt_status(err); u8 mgmt_err = mgmt_status(err);
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err); mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
goto done; goto done;
} }
@ -7174,7 +7290,7 @@ static void get_conn_info_complete(struct hci_dev *hdev, void *data, int err)
rp.max_tx_power = HCI_TX_POWER_INVALID; rp.max_tx_power = HCI_TX_POWER_INVALID;
} }
mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO, status, mgmt_cmd_complete(cmd->sk, cmd->hdev->id, MGMT_OP_GET_CONN_INFO, status,
&rp, sizeof(rp)); &rp, sizeof(rp));
mgmt_pending_free(cmd); mgmt_pending_free(cmd);
@ -7335,7 +7451,7 @@ static void get_clock_info_complete(struct hci_dev *hdev, void *data, int err)
} }
complete: complete:
mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp, mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status, &rp,
sizeof(rp)); sizeof(rp));
mgmt_pending_free(cmd); mgmt_pending_free(cmd);
@ -8035,10 +8151,6 @@ static void read_local_oob_ext_data_complete(struct hci_dev *hdev, void *data,
u8 status = mgmt_status(err); u8 status = mgmt_status(err);
u16 eir_len; u16 eir_len;
if (err == -ECANCELED ||
cmd != pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev))
return;
if (!status) { if (!status) {
if (!skb) if (!skb)
status = MGMT_STATUS_FAILED; status = MGMT_STATUS_FAILED;
@ -8145,7 +8257,7 @@ done:
kfree_skb(skb); kfree_skb(skb);
kfree(mgmt_rp); kfree(mgmt_rp);
mgmt_pending_remove(cmd); mgmt_pending_free(cmd);
} }
static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk, static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
@ -8154,7 +8266,7 @@ static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
struct mgmt_pending_cmd *cmd; struct mgmt_pending_cmd *cmd;
int err; int err;
cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev, cmd = mgmt_pending_new(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
cp, sizeof(*cp)); cp, sizeof(*cp));
if (!cmd) if (!cmd)
return -ENOMEM; return -ENOMEM;
@ -8585,10 +8697,10 @@ static void add_advertising_complete(struct hci_dev *hdev, void *data, int err)
rp.instance = cp->instance; rp.instance = cp->instance;
if (err) if (err)
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode,
mgmt_status(err)); mgmt_status(err));
else else
mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
mgmt_status(err), &rp, sizeof(rp)); mgmt_status(err), &rp, sizeof(rp));
add_adv_complete(hdev, cmd->sk, cp->instance, err); add_adv_complete(hdev, cmd->sk, cp->instance, err);
@ -8776,10 +8888,10 @@ static void add_ext_adv_params_complete(struct hci_dev *hdev, void *data,
hci_remove_adv_instance(hdev, cp->instance); hci_remove_adv_instance(hdev, cp->instance);
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode,
mgmt_status(err)); mgmt_status(err));
} else { } else {
mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
mgmt_status(err), &rp, sizeof(rp)); mgmt_status(err), &rp, sizeof(rp));
} }
@ -8926,10 +9038,10 @@ static void add_ext_adv_data_complete(struct hci_dev *hdev, void *data, int err)
rp.instance = cp->instance; rp.instance = cp->instance;
if (err) if (err)
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode,
mgmt_status(err)); mgmt_status(err));
else else
mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
mgmt_status(err), &rp, sizeof(rp)); mgmt_status(err), &rp, sizeof(rp));
mgmt_pending_free(cmd); mgmt_pending_free(cmd);
@ -9088,10 +9200,10 @@ static void remove_advertising_complete(struct hci_dev *hdev, void *data,
rp.instance = cp->instance; rp.instance = cp->instance;
if (err) if (err)
mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode,
mgmt_status(err)); mgmt_status(err));
else else
mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
MGMT_STATUS_SUCCESS, &rp, sizeof(rp)); MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
mgmt_pending_free(cmd); mgmt_pending_free(cmd);
@ -9363,7 +9475,7 @@ void mgmt_index_removed(struct hci_dev *hdev)
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
return; return;
mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &match); mgmt_pending_foreach(0, hdev, true, cmd_complete_rsp, &match);
if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) { if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev, NULL, 0, mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev, NULL, 0,
@ -9401,7 +9513,8 @@ void mgmt_power_on(struct hci_dev *hdev, int err)
hci_update_passive_scan(hdev); hci_update_passive_scan(hdev);
} }
mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, true, settings_rsp,
&match);
new_settings(hdev, match.sk); new_settings(hdev, match.sk);
@ -9416,7 +9529,8 @@ void __mgmt_power_off(struct hci_dev *hdev)
struct cmd_lookup match = { NULL, hdev }; struct cmd_lookup match = { NULL, hdev };
u8 zero_cod[] = { 0, 0, 0 }; u8 zero_cod[] = { 0, 0, 0 };
mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, true, settings_rsp,
&match);
/* If the power off is because of hdev unregistration let /* If the power off is because of hdev unregistration let
* use the appropriate INVALID_INDEX status. Otherwise use * use the appropriate INVALID_INDEX status. Otherwise use
@ -9430,7 +9544,7 @@ void __mgmt_power_off(struct hci_dev *hdev)
else else
match.mgmt_status = MGMT_STATUS_NOT_POWERED; match.mgmt_status = MGMT_STATUS_NOT_POWERED;
mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &match); mgmt_pending_foreach(0, hdev, true, cmd_complete_rsp, &match);
if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) { if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
@ -9671,7 +9785,6 @@ static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk); device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
cmd->cmd_complete(cmd, 0); cmd->cmd_complete(cmd, 0);
mgmt_pending_remove(cmd);
} }
bool mgmt_powering_down(struct hci_dev *hdev) bool mgmt_powering_down(struct hci_dev *hdev)
@ -9727,8 +9840,8 @@ void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
struct mgmt_cp_disconnect *cp; struct mgmt_cp_disconnect *cp;
struct mgmt_pending_cmd *cmd; struct mgmt_pending_cmd *cmd;
mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp, mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, true,
hdev); unpair_device_rsp, hdev);
cmd = pending_find(MGMT_OP_DISCONNECT, hdev); cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
if (!cmd) if (!cmd)
@ -9921,7 +10034,7 @@ void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
if (status) { if (status) {
u8 mgmt_err = mgmt_status(status); u8 mgmt_err = mgmt_status(status);
mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, true,
cmd_status_rsp, &mgmt_err); cmd_status_rsp, &mgmt_err);
return; return;
} }
@ -9931,8 +10044,8 @@ void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
else else
changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY); changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp, mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, true,
&match); settings_rsp, &match);
if (changed) if (changed)
new_settings(hdev, match.sk); new_settings(hdev, match.sk);
@ -9956,9 +10069,12 @@ void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
{ {
struct cmd_lookup match = { NULL, hdev, mgmt_status(status) }; struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match); mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, false, sk_lookup,
mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match); &match);
mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match); mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, false, sk_lookup,
&match);
mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, false, sk_lookup,
&match);
if (!status) { if (!status) {
mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,

View File

@ -217,30 +217,47 @@ int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode, struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode,
struct hci_dev *hdev) struct hci_dev *hdev)
{ {
struct mgmt_pending_cmd *cmd; struct mgmt_pending_cmd *cmd, *tmp;
list_for_each_entry(cmd, &hdev->mgmt_pending, list) { mutex_lock(&hdev->mgmt_pending_lock);
list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
if (hci_sock_get_channel(cmd->sk) != channel) if (hci_sock_get_channel(cmd->sk) != channel)
continue; continue;
if (cmd->opcode == opcode)
if (cmd->opcode == opcode) {
mutex_unlock(&hdev->mgmt_pending_lock);
return cmd; return cmd;
} }
}
mutex_unlock(&hdev->mgmt_pending_lock);
return NULL; return NULL;
} }
void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, bool remove,
void (*cb)(struct mgmt_pending_cmd *cmd, void *data), void (*cb)(struct mgmt_pending_cmd *cmd, void *data),
void *data) void *data)
{ {
struct mgmt_pending_cmd *cmd, *tmp; struct mgmt_pending_cmd *cmd, *tmp;
mutex_lock(&hdev->mgmt_pending_lock);
list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) { list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
if (opcode > 0 && cmd->opcode != opcode) if (opcode > 0 && cmd->opcode != opcode)
continue; continue;
if (remove)
list_del(&cmd->list);
cb(cmd, data); cb(cmd, data);
if (remove)
mgmt_pending_free(cmd);
} }
mutex_unlock(&hdev->mgmt_pending_lock);
} }
struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode, struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
@ -254,7 +271,7 @@ struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
return NULL; return NULL;
cmd->opcode = opcode; cmd->opcode = opcode;
cmd->index = hdev->id; cmd->hdev = hdev;
cmd->param = kmemdup(data, len, GFP_KERNEL); cmd->param = kmemdup(data, len, GFP_KERNEL);
if (!cmd->param) { if (!cmd->param) {
@ -280,7 +297,9 @@ struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
if (!cmd) if (!cmd)
return NULL; return NULL;
mutex_lock(&hdev->mgmt_pending_lock);
list_add_tail(&cmd->list, &hdev->mgmt_pending); list_add_tail(&cmd->list, &hdev->mgmt_pending);
mutex_unlock(&hdev->mgmt_pending_lock);
return cmd; return cmd;
} }
@ -294,10 +313,59 @@ void mgmt_pending_free(struct mgmt_pending_cmd *cmd)
void mgmt_pending_remove(struct mgmt_pending_cmd *cmd) void mgmt_pending_remove(struct mgmt_pending_cmd *cmd)
{ {
mutex_lock(&cmd->hdev->mgmt_pending_lock);
list_del(&cmd->list); list_del(&cmd->list);
mutex_unlock(&cmd->hdev->mgmt_pending_lock);
mgmt_pending_free(cmd); mgmt_pending_free(cmd);
} }
bool __mgmt_pending_listed(struct hci_dev *hdev, struct mgmt_pending_cmd *cmd)
{
struct mgmt_pending_cmd *tmp;
lockdep_assert_held(&hdev->mgmt_pending_lock);
if (!cmd)
return false;
list_for_each_entry(tmp, &hdev->mgmt_pending, list) {
if (cmd == tmp)
return true;
}
return false;
}
bool mgmt_pending_listed(struct hci_dev *hdev, struct mgmt_pending_cmd *cmd)
{
bool listed;
mutex_lock(&hdev->mgmt_pending_lock);
listed = __mgmt_pending_listed(hdev, cmd);
mutex_unlock(&hdev->mgmt_pending_lock);
return listed;
}
bool mgmt_pending_valid(struct hci_dev *hdev, struct mgmt_pending_cmd *cmd)
{
bool listed;
if (!cmd)
return false;
mutex_lock(&hdev->mgmt_pending_lock);
listed = __mgmt_pending_listed(hdev, cmd);
if (listed)
list_del(&cmd->list);
mutex_unlock(&hdev->mgmt_pending_lock);
return listed;
}
void mgmt_mesh_foreach(struct hci_dev *hdev, void mgmt_mesh_foreach(struct hci_dev *hdev,
void (*cb)(struct mgmt_mesh_tx *mesh_tx, void *data), void (*cb)(struct mgmt_mesh_tx *mesh_tx, void *data),
void *data, struct sock *sk) void *data, struct sock *sk)

View File

@ -33,7 +33,7 @@ struct mgmt_mesh_tx {
struct mgmt_pending_cmd { struct mgmt_pending_cmd {
struct list_head list; struct list_head list;
u16 opcode; u16 opcode;
int index; struct hci_dev *hdev;
void *param; void *param;
size_t param_len; size_t param_len;
struct sock *sk; struct sock *sk;
@ -54,7 +54,7 @@ int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode, struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode,
struct hci_dev *hdev); struct hci_dev *hdev);
void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, bool remove,
void (*cb)(struct mgmt_pending_cmd *cmd, void *data), void (*cb)(struct mgmt_pending_cmd *cmd, void *data),
void *data); void *data);
struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
@ -65,6 +65,9 @@ struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
void *data, u16 len); void *data, u16 len);
void mgmt_pending_free(struct mgmt_pending_cmd *cmd); void mgmt_pending_free(struct mgmt_pending_cmd *cmd);
void mgmt_pending_remove(struct mgmt_pending_cmd *cmd); void mgmt_pending_remove(struct mgmt_pending_cmd *cmd);
bool __mgmt_pending_listed(struct hci_dev *hdev, struct mgmt_pending_cmd *cmd);
bool mgmt_pending_listed(struct hci_dev *hdev, struct mgmt_pending_cmd *cmd);
bool mgmt_pending_valid(struct hci_dev *hdev, struct mgmt_pending_cmd *cmd);
void mgmt_mesh_foreach(struct hci_dev *hdev, void mgmt_mesh_foreach(struct hci_dev *hdev,
void (*cb)(struct mgmt_mesh_tx *mesh_tx, void *data), void (*cb)(struct mgmt_mesh_tx *mesh_tx, void *data),
void *data, struct sock *sk); void *data, struct sock *sk);

View File

@ -3162,6 +3162,7 @@ int tcp_disconnect(struct sock *sk, int flags)
struct inet_connection_sock *icsk = inet_csk(sk); struct inet_connection_sock *icsk = inet_csk(sk);
struct tcp_sock *tp = tcp_sk(sk); struct tcp_sock *tp = tcp_sk(sk);
int old_state = sk->sk_state; int old_state = sk->sk_state;
struct request_sock *req;
u32 seq; u32 seq;
if (old_state != TCP_CLOSE) if (old_state != TCP_CLOSE)
@ -3272,6 +3273,10 @@ int tcp_disconnect(struct sock *sk, int flags)
/* Clean up fastopen related fields */ /* Clean up fastopen related fields */
req = rcu_dereference_protected(tp->fastopen_rsk,
lockdep_sock_is_held(sk));
if (req)
reqsk_fastopen_remove(sk, req, false);
tcp_free_fastopen_req(tp); tcp_free_fastopen_req(tp);
inet->defer_connect = 0; inet->defer_connect = 0;
tp->fastopen_client_fail = 0; tp->fastopen_client_fail = 0;

View File

@ -7111,7 +7111,6 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
&foc, TCP_SYNACK_FASTOPEN, skb); &foc, TCP_SYNACK_FASTOPEN, skb);
/* Add the child socket directly into the accept queue */ /* Add the child socket directly into the accept queue */
if (!inet_csk_reqsk_queue_add(sk, req, fastopen_sk)) { if (!inet_csk_reqsk_queue_add(sk, req, fastopen_sk)) {
reqsk_fastopen_remove(fastopen_sk, req, false);
bh_unlock_sock(fastopen_sk); bh_unlock_sock(fastopen_sk);
sock_put(fastopen_sk); sock_put(fastopen_sk);
goto drop_and_free; goto drop_and_free;

View File

@ -1905,6 +1905,7 @@ cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
*/ */
f = rcu_access_pointer(new->pub.beacon_ies); f = rcu_access_pointer(new->pub.beacon_ies);
if (!new->pub.hidden_beacon_bss)
kfree_rcu((struct cfg80211_bss_ies *)f, rcu_head); kfree_rcu((struct cfg80211_bss_ies *)f, rcu_head);
return false; return false;
} }

View File

@ -1,3 +1,27 @@
* Tue Nov 25 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-611.11.1.el9_7]
- tcp: Don't call reqsk_fastopen_remove() in tcp_conn_request(). (Antoine Tenart) [RHEL-120668]
- tcp: Clear tcp_sk(sk)->fastopen_rsk in tcp_disconnect(). (Antoine Tenart) [RHEL-120668] {CVE-2025-39955}
- Bluetooth: MGMT: fix crash in set_mesh_sync and set_mesh_complete (CKI Backport Bot) [RHEL-122892] {CVE-2025-39981}
- Bluetooth: MGMT: Fix sparse errors (CKI Backport Bot) [RHEL-122892] {CVE-2025-39981}
- Bluetooth: MGMT: Fix possible UAFs (CKI Backport Bot) [RHEL-122892] {CVE-2025-39981}
- Bluetooth: hci_sync: fix set_local_name race condition (CKI Backport Bot) [RHEL-122892] {CVE-2025-39981}
- Bluetooth: MGMT: set_mesh: update LE scan interval and window (CKI Backport Bot) [RHEL-122892] {CVE-2025-39981}
- Bluetooth: MGMT: Protect mgmt_pending list with its own lock (CKI Backport Bot) [RHEL-122892] {CVE-2025-39981}
- Bluetooth: MGMT: Fix UAF on mgmt_remove_adv_monitor_complete (CKI Backport Bot) [RHEL-122892] {CVE-2025-39981}
- wifi: mt76: free pending offchannel tx frames on wcid cleanup (Jose Ignacio Tornos Martinez) [RHEL-123064]
- wifi: mt76: do not add non-sta wcid entries to the poll list (Jose Ignacio Tornos Martinez) [RHEL-123064]
- wifi: mt76: fix linked list corruption (Jose Ignacio Tornos Martinez) [RHEL-123064] {CVE-2025-39918}
Resolves: RHEL-120668, RHEL-122892, RHEL-123064
* Thu Nov 20 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-611.10.1.el9_7]
- ice: ice_adapter: release xa entry on adapter allocation failure (CKI Backport Bot) [RHEL-128469] {CVE-2025-40185}
- iommu/vt-d: Disallow dirty tracking if incoherent page walk (Eder Zulian) [RHEL-125478] {CVE-2025-40058}
- e1000e: fix heap overflow in e1000_set_eeprom (Corinna Vinschen) [RHEL-123111] {CVE-2025-39898}
- nfsd: handle get_client_locked() failure in nfsd4_setclientid_confirm() (CKI Backport Bot) [RHEL-125604] {CVE-2025-38724}
- wifi: cfg80211: fix use-after-free in cmp_bss() (CKI Backport Bot) [RHEL-122874] {CVE-2025-39864}
- platform/x86/intel: power-domains: Use topology_logical_package_id() for package ID (Jay Shin) [RHEL-116680]
Resolves: RHEL-116680, RHEL-122874, RHEL-123111, RHEL-125478, RHEL-125604, RHEL-128469
* Sat Nov 15 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-611.9.1.el9_7] * Sat Nov 15 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-611.9.1.el9_7]
- NFSv4: handle ERR_GRACE on delegation recalls (Olga Kornievskaia) [RHEL-124651] - NFSv4: handle ERR_GRACE on delegation recalls (Olga Kornievskaia) [RHEL-124651]
- nfsd: nfserr_jukebox in nlm_fopen should lead to a retry (Olga Kornievskaia) [RHEL-124651] - nfsd: nfserr_jukebox in nlm_fopen should lead to a retry (Olga Kornievskaia) [RHEL-124651]