Merge tag 'net-7.0-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net

Pull networking fixes from Jakub Kicinski:
 "Including fixes from wireless, Bluetooth and netfilter.

  Nothing too exciting here, mostly fixes for corner cases.

  Current release - fix to a fix:

   - bonding: prevent potential infinite loop in bond_header_parse()

  Current release - new code bugs:

   - wifi: mac80211: check tdls flag in ieee80211_tdls_oper

  Previous releases - regressions:

   - af_unix: give up GC if MSG_PEEK intervened

   - netfilter: conntrack: add missing netlink policy validations

   - NFC: nxp-nci: allow GPIOs to sleep"

* tag 'net-7.0-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (78 commits)
  MPTCP: fix lock class name family in pm_nl_create_listen_socket
  icmp: fix NULL pointer dereference in icmp_tag_validation()
  net: dsa: bcm_sf2: fix missing clk_disable_unprepare() in error paths
  net: shaper: protect from late creation of hierarchy
  net: shaper: protect late read accesses to the hierarchy
  net: mvpp2: guard flow control update with global_tx_fc in buffer switching
  nfnetlink_osf: validate individual option lengths in fingerprints
  netfilter: nf_tables: release flowtable after rcu grace period on error
  netfilter: bpf: defer hook memory release until rcu readers are done
  net: bonding: fix NULL deref in bond_debug_rlb_hash_show
  udp_tunnel: fix NULL deref caused by udp_sock_create6 when CONFIG_IPV6=n
  net/mlx5e: Fix race condition during IPSec ESN update
  net/mlx5e: Prevent concurrent access to IPSec ASO context
  net/mlx5: qos: Restrict RTNL area to avoid a lock cycle
  ipv6: add NULL checks for idev in SRv6 paths
  NFC: nxp-nci: allow GPIOs to sleep
  net: macb: fix uninitialized rx_fs_lock
  net: macb: fix use-after-free access to PTP clock
  netdevsim: drop PSP ext ref on forward failure
  wifi: mac80211: always free skb on ieee80211_tx_prepare_skb() failure
  ...
This commit is contained in:
Linus Torvalds
2026-03-19 11:25:40 -07:00
93 changed files with 735 additions and 460 deletions

View File

@@ -247,8 +247,8 @@ operations:
flags: [admin-perm]
do:
pre: net-shaper-nl-pre-doit
post: net-shaper-nl-post-doit
pre: net-shaper-nl-pre-doit-write
post: net-shaper-nl-post-doit-write
request:
attributes:
- ifindex
@@ -278,8 +278,8 @@ operations:
flags: [admin-perm]
do:
pre: net-shaper-nl-pre-doit
post: net-shaper-nl-post-doit
pre: net-shaper-nl-pre-doit-write
post: net-shaper-nl-post-doit-write
request:
attributes: *ns-binding
@@ -309,8 +309,8 @@ operations:
flags: [admin-perm]
do:
pre: net-shaper-nl-pre-doit
post: net-shaper-nl-post-doit
pre: net-shaper-nl-pre-doit-write
post: net-shaper-nl-post-doit-write
request:
attributes:
- ifindex

View File

@@ -787,6 +787,8 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
*/
if (soc_type == QCA_WCN3988)
rom_ver = ((soc_ver & 0x00000f00) >> 0x05) | (soc_ver & 0x0000000f);
else if (soc_type == QCA_WCN3998)
rom_ver = ((soc_ver & 0x0000f000) >> 0x07) | (soc_ver & 0x0000000f);
else
rom_ver = ((soc_ver & 0x00000f00) >> 0x04) | (soc_ver & 0x0000000f);

View File

@@ -257,9 +257,10 @@ static void fwnet_header_cache_update(struct hh_cache *hh,
memcpy((u8 *)hh->hh_data + HH_DATA_OFF(FWNET_HLEN), haddr, net->addr_len);
}
static int fwnet_header_parse(const struct sk_buff *skb, unsigned char *haddr)
static int fwnet_header_parse(const struct sk_buff *skb, const struct net_device *dev,
unsigned char *haddr)
{
memcpy(haddr, skb->dev->dev_addr, FWNET_ALEN);
memcpy(haddr, dev->dev_addr, FWNET_ALEN);
return FWNET_ALEN;
}

View File

@@ -34,11 +34,17 @@ static int bond_debug_rlb_hash_show(struct seq_file *m, void *v)
for (; hash_index != RLB_NULL_INDEX;
hash_index = client_info->used_next) {
client_info = &(bond_info->rx_hashtbl[hash_index]);
if (client_info->slave)
seq_printf(m, "%-15pI4 %-15pI4 %-17pM %s\n",
&client_info->ip_src,
&client_info->ip_dst,
&client_info->mac_dst,
client_info->slave->dev->name);
else
seq_printf(m, "%-15pI4 %-15pI4 %-17pM (none)\n",
&client_info->ip_src,
&client_info->ip_dst,
&client_info->mac_dst);
}
spin_unlock_bh(&bond->mode_lock);

View File

@@ -1530,9 +1530,11 @@ static int bond_header_create(struct sk_buff *skb, struct net_device *bond_dev,
return ret;
}
static int bond_header_parse(const struct sk_buff *skb, unsigned char *haddr)
static int bond_header_parse(const struct sk_buff *skb,
const struct net_device *dev,
unsigned char *haddr)
{
struct bonding *bond = netdev_priv(skb->dev);
struct bonding *bond = netdev_priv(dev);
const struct header_ops *slave_ops;
struct slave *slave;
int ret = 0;
@@ -1542,7 +1544,7 @@ static int bond_header_parse(const struct sk_buff *skb, unsigned char *haddr)
if (slave) {
slave_ops = READ_ONCE(slave->dev->header_ops);
if (slave_ops && slave_ops->parse)
ret = slave_ops->parse(skb, haddr);
ret = slave_ops->parse(skb, slave->dev, haddr);
}
rcu_read_unlock();
return ret;

View File

@@ -980,15 +980,19 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds)
ret = bcm_sf2_sw_rst(priv);
if (ret) {
pr_err("%s: failed to software reset switch\n", __func__);
if (!priv->wol_ports_mask)
clk_disable_unprepare(priv->clk);
return ret;
}
bcm_sf2_crossbar_setup(priv);
ret = bcm_sf2_cfp_resume(ds);
if (ret)
if (ret) {
if (!priv->wol_ports_mask)
clk_disable_unprepare(priv->clk);
return ret;
}
if (priv->hw_params.num_gphy == 1)
bcm_sf2_gphy_enable_set(ds, true);

View File

@@ -3083,7 +3083,6 @@ static void airoha_remove(struct platform_device *pdev)
if (!port)
continue;
airoha_dev_stop(port->dev);
unregister_netdev(port->dev);
airoha_metadata_dst_free(port);
}

View File

@@ -2929,6 +2929,8 @@ static int bnxt_async_event_process(struct bnxt *bp,
u16 type = (u16)BNXT_EVENT_BUF_PRODUCER_TYPE(data1);
u32 offset = BNXT_EVENT_BUF_PRODUCER_OFFSET(data2);
if (type >= ARRAY_SIZE(bp->bs_trace))
goto async_event_process_exit;
bnxt_bs_trace_check_wrap(&bp->bs_trace[type], offset);
goto async_event_process_exit;
}

View File

@@ -2146,7 +2146,7 @@ enum board_idx {
};
#define BNXT_TRACE_BUF_MAGIC_BYTE ((u8)0xbc)
#define BNXT_TRACE_MAX 11
#define BNXT_TRACE_MAX (DBG_LOG_BUFFER_FLUSH_REQ_TYPE_ERR_QPC_TRACE + 1)
struct bnxt_bs_trace_info {
u8 *magic_byte;

View File

@@ -123,7 +123,7 @@ static int bcmgenet_poll_wol_status(struct bcmgenet_priv *priv)
while (!(bcmgenet_rbuf_readl(priv, RBUF_STATUS)
& RBUF_STATUS_WOL)) {
retries++;
if (retries > 5) {
if (retries > 50) {
netdev_crit(dev, "polling wol mode timeout\n");
return -ETIMEDOUT;
}

View File

@@ -17029,6 +17029,13 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
return err;
}
static int tg3_is_default_mac_address(u8 *addr)
{
static const u8 default_mac_address[ETH_ALEN] = { 0x00, 0x10, 0x18, 0x00, 0x00, 0x00 };
return ether_addr_equal(default_mac_address, addr);
}
static int tg3_get_device_address(struct tg3 *tp, u8 *addr)
{
u32 hi, lo, mac_offset;
@@ -17102,6 +17109,10 @@ static int tg3_get_device_address(struct tg3 *tp, u8 *addr)
if (!is_valid_ether_addr(addr))
return -EINVAL;
if (tg3_is_default_mac_address(addr))
return device_get_mac_address(&tp->pdev->dev, addr);
return 0;
}

View File

@@ -2669,6 +2669,14 @@ static void macb_init_tieoff(struct macb *bp)
desc->ctrl = 0;
}
static void gem_init_rx_ring(struct macb_queue *queue)
{
queue->rx_tail = 0;
queue->rx_prepared_head = 0;
gem_rx_refill(queue);
}
static void gem_init_rings(struct macb *bp)
{
struct macb_queue *queue;
@@ -2686,10 +2694,7 @@ static void gem_init_rings(struct macb *bp)
queue->tx_head = 0;
queue->tx_tail = 0;
queue->rx_tail = 0;
queue->rx_prepared_head = 0;
gem_rx_refill(queue);
gem_init_rx_ring(queue);
}
macb_init_tieoff(bp);
@@ -3978,6 +3983,9 @@ static int gem_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
struct macb *bp = netdev_priv(netdev);
int ret;
if (!(netdev->hw_features & NETIF_F_NTUPLE))
return -EOPNOTSUPP;
switch (cmd->cmd) {
case ETHTOOL_SRXCLSRLINS:
if ((cmd->fs.location >= bp->max_tuples)
@@ -5947,8 +5955,18 @@ static int __maybe_unused macb_resume(struct device *dev)
rtnl_unlock();
}
if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC))
macb_init_buffers(bp);
for (q = 0, queue = bp->queues; q < bp->num_queues;
++q, ++queue) {
if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC)) {
if (macb_is_gem(bp))
gem_init_rx_ring(queue);
else
macb_init_rx_ring(queue);
}
napi_enable(&queue->napi_rx);
napi_enable(&queue->napi_tx);
}

View File

@@ -357,8 +357,10 @@ void gem_ptp_remove(struct net_device *ndev)
{
struct macb *bp = netdev_priv(ndev);
if (bp->ptp_clock)
if (bp->ptp_clock) {
ptp_clock_unregister(bp->ptp_clock);
bp->ptp_clock = NULL;
}
gem_ptp_clear_timer(bp);

View File

@@ -757,10 +757,13 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter,
adapter->num_vlan_filters++;
iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER);
} else if (f->state == IAVF_VLAN_REMOVE) {
/* IAVF_VLAN_REMOVE means that VLAN wasn't yet removed.
* We can safely only change the state here.
/* Re-add the filter since we cannot tell whether the
* pending delete has already been processed by the PF.
* A duplicate add is harmless.
*/
f->state = IAVF_VLAN_ACTIVE;
f->state = IAVF_VLAN_ADD;
iavf_schedule_aq_request(adapter,
IAVF_FLAG_AQ_ADD_VLAN_FILTER);
}
clearout:

View File

@@ -781,6 +781,8 @@ int igc_ptp_hwtstamp_set(struct net_device *netdev,
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack);
void igc_ptp_tx_hang(struct igc_adapter *adapter);
void igc_ptp_clear_xsk_tx_tstamp_queue(struct igc_adapter *adapter,
u16 queue_id);
void igc_ptp_read(struct igc_adapter *adapter, struct timespec64 *ts);
void igc_ptp_tx_tstamp_event(struct igc_adapter *adapter);

View File

@@ -264,6 +264,13 @@ static void igc_clean_tx_ring(struct igc_ring *tx_ring)
/* reset next_to_use and next_to_clean */
tx_ring->next_to_use = 0;
tx_ring->next_to_clean = 0;
/* Clear any lingering XSK TX timestamp requests */
if (test_bit(IGC_RING_FLAG_TX_HWTSTAMP, &tx_ring->flags)) {
struct igc_adapter *adapter = netdev_priv(tx_ring->netdev);
igc_ptp_clear_xsk_tx_tstamp_queue(adapter, tx_ring->queue_index);
}
}
/**
@@ -1730,11 +1737,8 @@ static netdev_tx_t igc_xmit_frame(struct sk_buff *skb,
/* The minimum packet size with TCTL.PSP set is 17 so pad the skb
* in order to meet this minimum size requirement.
*/
if (skb->len < 17) {
if (skb_padto(skb, 17))
if (skb_put_padto(skb, 17))
return NETDEV_TX_OK;
skb->len = 17;
}
return igc_xmit_frame_ring(skb, igc_tx_queue_mapping(adapter, skb));
}

View File

@@ -577,6 +577,39 @@ static void igc_ptp_clear_tx_tstamp(struct igc_adapter *adapter)
spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags);
}
/**
* igc_ptp_clear_xsk_tx_tstamp_queue - Clear pending XSK TX timestamps for a queue
* @adapter: Board private structure
* @queue_id: TX queue index to clear timestamps for
*
* Iterates over all TX timestamp registers and releases any pending
* timestamp requests associated with the given TX queue. This is
* called when an XDP pool is being disabled to ensure no stale
* timestamp references remain.
*/
void igc_ptp_clear_xsk_tx_tstamp_queue(struct igc_adapter *adapter, u16 queue_id)
{
unsigned long flags;
int i;
spin_lock_irqsave(&adapter->ptp_tx_lock, flags);
for (i = 0; i < IGC_MAX_TX_TSTAMP_REGS; i++) {
struct igc_tx_timestamp_request *tstamp = &adapter->tx_tstamp[i];
if (tstamp->buffer_type != IGC_TX_BUFFER_TYPE_XSK)
continue;
if (tstamp->xsk_queue_index != queue_id)
continue;
if (!tstamp->xsk_tx_buffer)
continue;
igc_ptp_free_tx_buffer(adapter, tstamp);
}
spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags);
}
static void igc_ptp_disable_tx_timestamp(struct igc_adapter *adapter)
{
struct igc_hw *hw = &adapter->hw;

View File

@@ -433,17 +433,21 @@ libie_debugfs_module_write(struct file *filp, const char __user *buf,
module = libie_find_module_by_dentry(fwlog->debugfs_modules, dentry);
if (module < 0) {
dev_info(dev, "unknown module\n");
return -EINVAL;
count = -EINVAL;
goto free_cmd_buf;
}
cnt = sscanf(cmd_buf, "%s", user_val);
if (cnt != 1)
return -EINVAL;
if (cnt != 1) {
count = -EINVAL;
goto free_cmd_buf;
}
log_level = sysfs_match_string(libie_fwlog_level_string, user_val);
if (log_level < 0) {
dev_info(dev, "unknown log level '%s'\n", user_val);
return -EINVAL;
count = -EINVAL;
goto free_cmd_buf;
}
if (module != LIBIE_AQC_FW_LOG_ID_MAX) {
@@ -458,6 +462,9 @@ libie_debugfs_module_write(struct file *filp, const char __user *buf,
fwlog->cfg.module_entries[i].log_level = log_level;
}
free_cmd_buf:
kfree(cmd_buf);
return count;
}
@@ -515,23 +522,31 @@ libie_debugfs_nr_messages_write(struct file *filp, const char __user *buf,
return PTR_ERR(cmd_buf);
ret = sscanf(cmd_buf, "%s", user_val);
if (ret != 1)
return -EINVAL;
if (ret != 1) {
count = -EINVAL;
goto free_cmd_buf;
}
ret = kstrtos16(user_val, 0, &nr_messages);
if (ret)
return ret;
if (ret) {
count = ret;
goto free_cmd_buf;
}
if (nr_messages < LIBIE_AQC_FW_LOG_MIN_RESOLUTION ||
nr_messages > LIBIE_AQC_FW_LOG_MAX_RESOLUTION) {
dev_err(dev, "Invalid FW log number of messages %d, value must be between %d - %d\n",
nr_messages, LIBIE_AQC_FW_LOG_MIN_RESOLUTION,
LIBIE_AQC_FW_LOG_MAX_RESOLUTION);
return -EINVAL;
count = -EINVAL;
goto free_cmd_buf;
}
fwlog->cfg.log_resolution = nr_messages;
free_cmd_buf:
kfree(cmd_buf);
return count;
}
@@ -588,8 +603,10 @@ libie_debugfs_enable_write(struct file *filp, const char __user *buf,
return PTR_ERR(cmd_buf);
ret = sscanf(cmd_buf, "%s", user_val);
if (ret != 1)
return -EINVAL;
if (ret != 1) {
ret = -EINVAL;
goto free_cmd_buf;
}
ret = kstrtobool(user_val, &enable);
if (ret)
@@ -624,6 +641,8 @@ enable_write_error:
*/
if (WARN_ON(ret != (ssize_t)count && ret >= 0))
ret = -EIO;
free_cmd_buf:
kfree(cmd_buf);
return ret;
}
@@ -682,8 +701,10 @@ libie_debugfs_log_size_write(struct file *filp, const char __user *buf,
return PTR_ERR(cmd_buf);
ret = sscanf(cmd_buf, "%s", user_val);
if (ret != 1)
return -EINVAL;
if (ret != 1) {
ret = -EINVAL;
goto free_cmd_buf;
}
index = sysfs_match_string(libie_fwlog_log_size, user_val);
if (index < 0) {
@@ -712,6 +733,8 @@ log_size_write_error:
*/
if (WARN_ON(ret != (ssize_t)count && ret >= 0))
ret = -EIO;
free_cmd_buf:
kfree(cmd_buf);
return ret;
}

View File

@@ -5016,7 +5016,7 @@ static int mvpp2_bm_switch_buffers(struct mvpp2 *priv, bool percpu)
if (priv->percpu_pools)
numbufs = port->nrxqs * 2;
if (change_percpu)
if (change_percpu && priv->global_tx_fc)
mvpp2_bm_pool_update_priv_fc(priv, false);
for (i = 0; i < numbufs; i++)
@@ -5041,7 +5041,7 @@ static int mvpp2_bm_switch_buffers(struct mvpp2 *priv, bool percpu)
mvpp2_open(port->dev);
}
if (change_percpu)
if (change_percpu && priv->global_tx_fc)
mvpp2_bm_pool_update_priv_fc(priv, true);
return 0;

View File

@@ -287,6 +287,7 @@ struct mlx5e_ipsec_sa_entry {
struct mlx5e_ipsec_dwork *dwork;
struct mlx5e_ipsec_limits limits;
u32 rx_mapped_id;
u8 ctx[MLX5_ST_SZ_BYTES(ipsec_aso)];
};
struct mlx5_accel_pol_xfrm_attrs {

View File

@@ -310,10 +310,11 @@ static void mlx5e_ipsec_aso_update(struct mlx5e_ipsec_sa_entry *sa_entry,
mlx5e_ipsec_aso_query(sa_entry, data);
}
static void mlx5e_ipsec_update_esn_state(struct mlx5e_ipsec_sa_entry *sa_entry,
u32 mode_param)
static void
mlx5e_ipsec_update_esn_state(struct mlx5e_ipsec_sa_entry *sa_entry,
u32 mode_param,
struct mlx5_accel_esp_xfrm_attrs *attrs)
{
struct mlx5_accel_esp_xfrm_attrs attrs = {};
struct mlx5_wqe_aso_ctrl_seg data = {};
if (mode_param < MLX5E_IPSEC_ESN_SCOPE_MID) {
@@ -323,18 +324,7 @@ static void mlx5e_ipsec_update_esn_state(struct mlx5e_ipsec_sa_entry *sa_entry,
sa_entry->esn_state.overlap = 1;
}
mlx5e_ipsec_build_accel_xfrm_attrs(sa_entry, &attrs);
/* It is safe to execute the modify below unlocked since the only flows
* that could affect this HW object, are create, destroy and this work.
*
* Creation flow can't co-exist with this modify work, the destruction
* flow would cancel this work, and this work is a single entity that
* can't conflict with it self.
*/
spin_unlock_bh(&sa_entry->x->lock);
mlx5_accel_esp_modify_xfrm(sa_entry, &attrs);
spin_lock_bh(&sa_entry->x->lock);
mlx5e_ipsec_build_accel_xfrm_attrs(sa_entry, attrs);
data.data_offset_condition_operand =
MLX5_IPSEC_ASO_REMOVE_FLOW_PKT_CNT_OFFSET;
@@ -370,20 +360,18 @@ static void mlx5e_ipsec_aso_update_soft(struct mlx5e_ipsec_sa_entry *sa_entry,
static void mlx5e_ipsec_handle_limits(struct mlx5e_ipsec_sa_entry *sa_entry)
{
struct mlx5_accel_esp_xfrm_attrs *attrs = &sa_entry->attrs;
struct mlx5e_ipsec *ipsec = sa_entry->ipsec;
struct mlx5e_ipsec_aso *aso = ipsec->aso;
bool soft_arm, hard_arm;
u64 hard_cnt;
lockdep_assert_held(&sa_entry->x->lock);
soft_arm = !MLX5_GET(ipsec_aso, aso->ctx, soft_lft_arm);
hard_arm = !MLX5_GET(ipsec_aso, aso->ctx, hard_lft_arm);
soft_arm = !MLX5_GET(ipsec_aso, sa_entry->ctx, soft_lft_arm);
hard_arm = !MLX5_GET(ipsec_aso, sa_entry->ctx, hard_lft_arm);
if (!soft_arm && !hard_arm)
/* It is not lifetime event */
return;
hard_cnt = MLX5_GET(ipsec_aso, aso->ctx, remove_flow_pkt_cnt);
hard_cnt = MLX5_GET(ipsec_aso, sa_entry->ctx, remove_flow_pkt_cnt);
if (!hard_cnt || hard_arm) {
/* It is possible to see packet counter equal to zero without
* hard limit event armed. Such situation can be if packet
@@ -453,11 +441,11 @@ static void mlx5e_ipsec_handle_event(struct work_struct *_work)
struct mlx5e_ipsec_work *work =
container_of(_work, struct mlx5e_ipsec_work, work);
struct mlx5e_ipsec_sa_entry *sa_entry = work->data;
struct mlx5_accel_esp_xfrm_attrs tmp = {};
struct mlx5_accel_esp_xfrm_attrs *attrs;
struct mlx5e_ipsec_aso *aso;
bool need_modify = false;
int ret;
aso = sa_entry->ipsec->aso;
attrs = &sa_entry->attrs;
spin_lock_bh(&sa_entry->x->lock);
@@ -465,18 +453,22 @@ static void mlx5e_ipsec_handle_event(struct work_struct *_work)
if (ret)
goto unlock;
if (attrs->replay_esn.trigger &&
!MLX5_GET(ipsec_aso, aso->ctx, esn_event_arm)) {
u32 mode_param = MLX5_GET(ipsec_aso, aso->ctx, mode_parameter);
mlx5e_ipsec_update_esn_state(sa_entry, mode_param);
}
if (attrs->lft.soft_packet_limit != XFRM_INF)
mlx5e_ipsec_handle_limits(sa_entry);
if (attrs->replay_esn.trigger &&
!MLX5_GET(ipsec_aso, sa_entry->ctx, esn_event_arm)) {
u32 mode_param = MLX5_GET(ipsec_aso, sa_entry->ctx,
mode_parameter);
mlx5e_ipsec_update_esn_state(sa_entry, mode_param, &tmp);
need_modify = true;
}
unlock:
spin_unlock_bh(&sa_entry->x->lock);
if (need_modify)
mlx5_accel_esp_modify_xfrm(sa_entry, &tmp);
kfree(work);
}
@@ -629,6 +621,8 @@ int mlx5e_ipsec_aso_query(struct mlx5e_ipsec_sa_entry *sa_entry,
/* We are in atomic context */
udelay(10);
} while (ret && time_is_after_jiffies(expires));
if (!ret)
memcpy(sa_entry->ctx, aso->ctx, MLX5_ST_SZ_BYTES(ipsec_aso));
spin_unlock_bh(&aso->lock);
return ret;
}

View File

@@ -1489,24 +1489,24 @@ out:
return err;
}
static u32 mlx5_esw_qos_lag_link_speed_get_locked(struct mlx5_core_dev *mdev)
static u32 mlx5_esw_qos_lag_link_speed_get(struct mlx5_core_dev *mdev,
bool take_rtnl)
{
struct ethtool_link_ksettings lksettings;
struct net_device *slave, *master;
u32 speed = SPEED_UNKNOWN;
/* Lock ensures a stable reference to master and slave netdevice
* while port speed of master is queried.
*/
ASSERT_RTNL();
slave = mlx5_uplink_netdev_get(mdev);
if (!slave)
goto out;
if (take_rtnl)
rtnl_lock();
master = netdev_master_upper_dev_get(slave);
if (master && !__ethtool_get_link_ksettings(master, &lksettings))
speed = lksettings.base.speed;
if (take_rtnl)
rtnl_unlock();
out:
mlx5_uplink_netdev_put(mdev, slave);
@@ -1514,20 +1514,15 @@ out:
}
static int mlx5_esw_qos_max_link_speed_get(struct mlx5_core_dev *mdev, u32 *link_speed_max,
bool hold_rtnl_lock, struct netlink_ext_ack *extack)
bool take_rtnl,
struct netlink_ext_ack *extack)
{
int err;
if (!mlx5_lag_is_active(mdev))
goto skip_lag;
if (hold_rtnl_lock)
rtnl_lock();
*link_speed_max = mlx5_esw_qos_lag_link_speed_get_locked(mdev);
if (hold_rtnl_lock)
rtnl_unlock();
*link_speed_max = mlx5_esw_qos_lag_link_speed_get(mdev, take_rtnl);
if (*link_speed_max != (u32)SPEED_UNKNOWN)
return 0;

View File

@@ -814,9 +814,6 @@ void mana_hwc_destroy_channel(struct gdma_context *gc)
gc->max_num_cqs = 0;
}
kfree(hwc->caller_ctx);
hwc->caller_ctx = NULL;
if (hwc->txq)
mana_hwc_destroy_wq(hwc, hwc->txq);
@@ -826,6 +823,9 @@ void mana_hwc_destroy_channel(struct gdma_context *gc)
if (hwc->cq)
mana_hwc_destroy_cq(hwc->gdma_dev->gdma_context, hwc->cq);
kfree(hwc->caller_ctx);
hwc->caller_ctx = NULL;
mana_gd_free_res_map(&hwc->inflight_msg_res);
hwc->num_inflight_msg = 0;

View File

@@ -1075,6 +1075,11 @@ static int emac_rx_packet(struct prueth_emac *emac, u32 flow_id, u32 *xdp_state)
xdp_prepare_buff(&xdp, pa, PRUETH_HEADROOM, pkt_len, false);
*xdp_state = emac_run_xdp(emac, &xdp, &pkt_len);
if (*xdp_state == ICSSG_XDP_CONSUMED) {
page_pool_recycle_direct(pool, page);
goto requeue;
}
if (*xdp_state != ICSSG_XDP_PASS)
goto requeue;
headroom = xdp.data - xdp.data_hard_start;

View File

@@ -109,8 +109,11 @@ static int nsim_forward_skb(struct net_device *tx_dev,
int ret;
ret = __dev_forward_skb(rx_dev, skb);
if (ret)
if (ret) {
if (psp_ext)
__skb_ext_put(psp_ext);
return ret;
}
nsim_psp_handle_ext(skb, psp_ext);

View File

@@ -1395,13 +1395,13 @@ static int aqc111_suspend(struct usb_interface *intf, pm_message_t message)
aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC,
SFR_MEDIUM_STATUS_MODE, 2, &reg16);
aqc111_write_cmd(dev, AQ_WOL_CFG, 0, 0,
aqc111_write_cmd_nopm(dev, AQ_WOL_CFG, 0, 0,
WOL_CFG_SIZE, &wol_cfg);
aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0,
aqc111_write32_cmd_nopm(dev, AQ_PHY_OPS, 0, 0,
&aqc111_data->phy_cfg);
} else {
aqc111_data->phy_cfg |= AQ_LOW_POWER;
aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0,
aqc111_write32_cmd_nopm(dev, AQ_PHY_OPS, 0, 0,
&aqc111_data->phy_cfg);
/* Disable RX path */

View File

@@ -1656,6 +1656,7 @@ int cdc_ncm_rx_verify_ndp16(struct sk_buff *skb_in, int ndpoffset)
struct usbnet *dev = netdev_priv(skb_in->dev);
struct usb_cdc_ncm_ndp16 *ndp16;
int ret = -EINVAL;
size_t ndp_len;
if ((ndpoffset + sizeof(struct usb_cdc_ncm_ndp16)) > skb_in->len) {
netif_dbg(dev, rx_err, dev->net, "invalid NDP offset <%u>\n",
@@ -1675,8 +1676,8 @@ int cdc_ncm_rx_verify_ndp16(struct sk_buff *skb_in, int ndpoffset)
sizeof(struct usb_cdc_ncm_dpe16));
ret--; /* we process NDP entries except for the last one */
if ((sizeof(struct usb_cdc_ncm_ndp16) +
ret * (sizeof(struct usb_cdc_ncm_dpe16))) > skb_in->len) {
ndp_len = struct_size_t(struct usb_cdc_ncm_ndp16, dpe16, ret);
if (ndpoffset + ndp_len > skb_in->len) {
netif_dbg(dev, rx_err, dev->net, "Invalid nframes = %d\n", ret);
ret = -EINVAL;
}
@@ -1692,6 +1693,7 @@ int cdc_ncm_rx_verify_ndp32(struct sk_buff *skb_in, int ndpoffset)
struct usbnet *dev = netdev_priv(skb_in->dev);
struct usb_cdc_ncm_ndp32 *ndp32;
int ret = -EINVAL;
size_t ndp_len;
if ((ndpoffset + sizeof(struct usb_cdc_ncm_ndp32)) > skb_in->len) {
netif_dbg(dev, rx_err, dev->net, "invalid NDP offset <%u>\n",
@@ -1711,8 +1713,8 @@ int cdc_ncm_rx_verify_ndp32(struct sk_buff *skb_in, int ndpoffset)
sizeof(struct usb_cdc_ncm_dpe32));
ret--; /* we process NDP entries except for the last one */
if ((sizeof(struct usb_cdc_ncm_ndp32) +
ret * (sizeof(struct usb_cdc_ncm_dpe32))) > skb_in->len) {
ndp_len = struct_size_t(struct usb_cdc_ncm_ndp32, dpe32, ret);
if (ndpoffset + ndp_len > skb_in->len) {
netif_dbg(dev, rx_err, dev->net, "Invalid nframes = %d\n", ret);
ret = -EINVAL;
}

View File

@@ -1006,7 +1006,7 @@ static void ath_scan_send_probe(struct ath_softc *sc,
skb_set_queue_mapping(skb, IEEE80211_AC_VO);
if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, NULL))
goto error;
return;
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
if (ath_tx_start(sc->hw, skb, &txctl))
@@ -1119,10 +1119,8 @@ ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
skb->priority = 7;
skb_set_queue_mapping(skb, IEEE80211_AC_VO);
if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) {
dev_kfree_skb_any(skb);
if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta))
return false;
}
break;
default:
return false;

View File

@@ -63,10 +63,8 @@ mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid)
rcu_read_lock();
if (!ieee80211_tx_prepare_skb(phy->hw, vif, skb, band, NULL)) {
ieee80211_free_txskb(phy->hw, skb);
if (!ieee80211_tx_prepare_skb(phy->hw, vif, skb, band, NULL))
goto out;
}
info = IEEE80211_SKB_CB(skb);
if (req->no_cck)

View File

@@ -210,7 +210,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
if (skb_headroom(skb) < (total_len - skb->len) &&
pskb_expand_head(skb, (total_len - skb->len), 0, GFP_ATOMIC)) {
wl1271_free_tx_id(wl, id);
return -EAGAIN;
return -ENOMEM;
}
desc = skb_push(skb, total_len - skb->len);

View File

@@ -3021,7 +3021,6 @@ static void hw_scan_work(struct work_struct *work)
hwsim->tmp_chan->band,
NULL)) {
rcu_read_unlock();
kfree_skb(probe);
continue;
}
@@ -6489,7 +6488,7 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
if (info->attrs[HWSIM_ATTR_PMSR_SUPPORT]) {
struct cfg80211_pmsr_capabilities *pmsr_capa;
pmsr_capa = kmalloc_obj(*pmsr_capa);
pmsr_capa = kzalloc_obj(*pmsr_capa);
if (!pmsr_capa) {
ret = -ENOMEM;
goto out_free;

View File

@@ -47,8 +47,8 @@ static int nxp_nci_i2c_set_mode(void *phy_id,
{
struct nxp_nci_i2c_phy *phy = (struct nxp_nci_i2c_phy *) phy_id;
gpiod_set_value(phy->gpiod_fw, (mode == NXP_NCI_MODE_FW) ? 1 : 0);
gpiod_set_value(phy->gpiod_en, (mode != NXP_NCI_MODE_COLD) ? 1 : 0);
gpiod_set_value_cansleep(phy->gpiod_fw, (mode == NXP_NCI_MODE_FW) ? 1 : 0);
gpiod_set_value_cansleep(phy->gpiod_en, (mode != NXP_NCI_MODE_COLD) ? 1 : 0);
usleep_range(10000, 15000);
if (mode == NXP_NCI_MODE_COLD)

View File

@@ -42,7 +42,8 @@ extern const struct header_ops eth_header_ops;
int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
const void *daddr, const void *saddr, unsigned len);
int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr);
int eth_header_parse(const struct sk_buff *skb, const struct net_device *dev,
unsigned char *haddr);
int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh,
__be16 type);
void eth_header_cache_update(struct hh_cache *hh, const struct net_device *dev,

View File

@@ -40,7 +40,8 @@ static inline struct ethhdr *inner_eth_hdr(const struct sk_buff *skb)
return (struct ethhdr *)skb_inner_mac_header(skb);
}
int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr);
int eth_header_parse(const struct sk_buff *skb, const struct net_device *dev,
unsigned char *haddr);
extern ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len);

View File

@@ -311,7 +311,9 @@ struct header_ops {
int (*create) (struct sk_buff *skb, struct net_device *dev,
unsigned short type, const void *daddr,
const void *saddr, unsigned int len);
int (*parse)(const struct sk_buff *skb, unsigned char *haddr);
int (*parse)(const struct sk_buff *skb,
const struct net_device *dev,
unsigned char *haddr);
int (*cache)(const struct neighbour *neigh, struct hh_cache *hh, __be16 type);
void (*cache_update)(struct hh_cache *hh,
const struct net_device *dev,
@@ -2155,6 +2157,7 @@ struct net_device {
unsigned long state;
unsigned int flags;
unsigned short hard_header_len;
enum netdev_stat_type pcpu_stat_type:8;
netdev_features_t features;
struct inet6_dev __rcu *ip6_ptr;
__cacheline_group_end(net_device_read_txrx);
@@ -2404,8 +2407,6 @@ struct net_device {
void *ml_priv;
enum netdev_ml_priv_type ml_priv_type;
enum netdev_stat_type pcpu_stat_type:8;
#if IS_ENABLED(CONFIG_GARP)
struct garp_port __rcu *garp_port;
#endif
@@ -3446,7 +3447,7 @@ static inline int dev_parse_header(const struct sk_buff *skb,
if (!dev->header_ops || !dev->header_ops->parse)
return 0;
return dev->header_ops->parse(skb, haddr);
return dev->header_ops->parse(skb, dev, haddr);
}
static inline __be16 dev_parse_header_protocol(const struct sk_buff *skb)

View File

@@ -665,6 +665,17 @@ static inline int iptunnel_pull_offloads(struct sk_buff *skb)
static inline void iptunnel_xmit_stats(struct net_device *dev, int pkt_len)
{
if (pkt_len > 0) {
if (dev->pcpu_stat_type == NETDEV_PCPU_STAT_DSTATS) {
struct pcpu_dstats *dstats = get_cpu_ptr(dev->dstats);
u64_stats_update_begin(&dstats->syncp);
u64_stats_add(&dstats->tx_bytes, pkt_len);
u64_stats_inc(&dstats->tx_packets);
u64_stats_update_end(&dstats->syncp);
put_cpu_ptr(dstats);
return;
}
if (dev->pcpu_stat_type == NETDEV_PCPU_STAT_TSTATS) {
struct pcpu_sw_netstats *tstats = get_cpu_ptr(dev->tstats);
u64_stats_update_begin(&tstats->syncp);
@@ -674,6 +685,11 @@ static inline void iptunnel_xmit_stats(struct net_device *dev, int pkt_len)
put_cpu_ptr(tstats);
return;
}
pr_err_once("iptunnel_xmit_stats pcpu_stat_type=%d\n",
dev->pcpu_stat_type);
WARN_ON_ONCE(1);
return;
}
if (pkt_len < 0) {
DEV_STATS_INC(dev, tx_errors);

View File

@@ -7407,7 +7407,9 @@ void ieee80211_report_wowlan_wakeup(struct ieee80211_vif *vif,
* @band: the band to transmit on
* @sta: optional pointer to get the station to send the frame to
*
* Return: %true if the skb was prepared, %false otherwise
* Return: %true if the skb was prepared, %false otherwise.
* On failure, the skb is freed by this function; callers must not
* free it again.
*
* Note: must be called under RCU lock
*/

View File

@@ -277,8 +277,6 @@ struct nft_userdata {
unsigned char data[];
};
#define NFT_SET_ELEM_INTERNAL_LAST 0x1
/* placeholder structure for opaque set element backend representation. */
struct nft_elem_priv { };
@@ -288,7 +286,6 @@ struct nft_elem_priv { };
* @key: element key
* @key_end: closing element key
* @data: element data
* @flags: flags
* @priv: element private data and extensions
*/
struct nft_set_elem {
@@ -304,7 +301,6 @@ struct nft_set_elem {
u32 buf[NFT_DATA_VALUE_MAXLEN / sizeof(u32)];
struct nft_data val;
} data;
u32 flags;
struct nft_elem_priv *priv;
};
@@ -878,6 +874,8 @@ struct nft_elem_priv *nft_set_elem_init(const struct nft_set *set,
u64 timeout, u64 expiration, gfp_t gfp);
int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set,
struct nft_expr *expr_array[]);
void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
struct nft_set_elem_expr *elem_expr);
void nft_set_elem_destroy(const struct nft_set *set,
const struct nft_elem_priv *elem_priv,
bool destroy_expr);

View File

@@ -716,6 +716,34 @@ void qdisc_destroy(struct Qdisc *qdisc);
void qdisc_put(struct Qdisc *qdisc);
void qdisc_put_unlocked(struct Qdisc *qdisc);
void qdisc_tree_reduce_backlog(struct Qdisc *qdisc, int n, int len);
static inline void dev_reset_queue(struct net_device *dev,
struct netdev_queue *dev_queue,
void *_unused)
{
struct Qdisc *qdisc;
bool nolock;
qdisc = rtnl_dereference(dev_queue->qdisc_sleeping);
if (!qdisc)
return;
nolock = qdisc->flags & TCQ_F_NOLOCK;
if (nolock)
spin_lock_bh(&qdisc->seqlock);
spin_lock_bh(qdisc_lock(qdisc));
qdisc_reset(qdisc);
spin_unlock_bh(qdisc_lock(qdisc));
if (nolock) {
clear_bit(__QDISC_STATE_MISSED, &qdisc->state);
clear_bit(__QDISC_STATE_DRAINING, &qdisc->state);
spin_unlock_bh(&qdisc->seqlock);
}
}
#ifdef CONFIG_NET_SCHED
int qdisc_offload_dump_helper(struct Qdisc *q, enum tc_setup_type type,
void *type_data);
@@ -1429,6 +1457,11 @@ void mini_qdisc_pair_init(struct mini_Qdisc_pair *miniqp, struct Qdisc *qdisc,
void mini_qdisc_pair_block_init(struct mini_Qdisc_pair *miniqp,
struct tcf_block *block);
static inline bool mini_qdisc_pair_inited(struct mini_Qdisc_pair *miniqp)
{
return !!miniqp->p_miniq;
}
void mq_change_real_num_tx(struct Qdisc *sch, unsigned int new_real_tx);
int sch_frag_xmit_hook(struct sk_buff *skb, int (*xmit)(struct sk_buff *skb));

View File

@@ -52,7 +52,7 @@ int udp_sock_create6(struct net *net, struct udp_port_cfg *cfg,
static inline int udp_sock_create6(struct net *net, struct udp_port_cfg *cfg,
struct socket **sockp)
{
return 0;
return -EPFNOSUPPORT;
}
#endif

View File

@@ -154,10 +154,19 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
/* 0x01 is topology change */
priv = netdev_priv(dev);
atm_force_charge(priv->lecd, skb2->truesize);
sk = sk_atm(priv->lecd);
struct atm_vcc *vcc;
rcu_read_lock();
vcc = rcu_dereference(priv->lecd);
if (vcc) {
atm_force_charge(vcc, skb2->truesize);
sk = sk_atm(vcc);
skb_queue_tail(&sk->sk_receive_queue, skb2);
sk->sk_data_ready(sk);
} else {
dev_kfree_skb(skb2);
}
rcu_read_unlock();
}
}
#endif /* IS_ENABLED(CONFIG_BRIDGE) */
@@ -216,7 +225,7 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
int is_rdesc;
pr_debug("called\n");
if (!priv->lecd) {
if (!rcu_access_pointer(priv->lecd)) {
pr_info("%s:No lecd attached\n", dev->name);
dev->stats.tx_errors++;
netif_stop_queue(dev);
@@ -449,10 +458,19 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
break;
skb2->len = sizeof(struct atmlec_msg);
skb_copy_to_linear_data(skb2, mesg, sizeof(*mesg));
atm_force_charge(priv->lecd, skb2->truesize);
sk = sk_atm(priv->lecd);
struct atm_vcc *vcc;
rcu_read_lock();
vcc = rcu_dereference(priv->lecd);
if (vcc) {
atm_force_charge(vcc, skb2->truesize);
sk = sk_atm(vcc);
skb_queue_tail(&sk->sk_receive_queue, skb2);
sk->sk_data_ready(sk);
} else {
dev_kfree_skb(skb2);
}
rcu_read_unlock();
}
}
#endif /* IS_ENABLED(CONFIG_BRIDGE) */
@@ -468,23 +486,16 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
static void lec_atm_close(struct atm_vcc *vcc)
{
struct sk_buff *skb;
struct net_device *dev = (struct net_device *)vcc->proto_data;
struct lec_priv *priv = netdev_priv(dev);
priv->lecd = NULL;
rcu_assign_pointer(priv->lecd, NULL);
synchronize_rcu();
/* Do something needful? */
netif_stop_queue(dev);
lec_arp_destroy(priv);
if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
pr_info("%s closing with messages pending\n", dev->name);
while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue))) {
atm_return(vcc, skb->truesize);
dev_kfree_skb(skb);
}
pr_info("%s: Shut down!\n", dev->name);
module_put(THIS_MODULE);
}
@@ -510,12 +521,14 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
const unsigned char *mac_addr, const unsigned char *atm_addr,
struct sk_buff *data)
{
struct atm_vcc *vcc;
struct sock *sk;
struct sk_buff *skb;
struct atmlec_msg *mesg;
if (!priv || !priv->lecd)
if (!priv || !rcu_access_pointer(priv->lecd))
return -1;
skb = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
if (!skb)
return -1;
@@ -532,18 +545,27 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
if (atm_addr)
memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN);
atm_force_charge(priv->lecd, skb->truesize);
sk = sk_atm(priv->lecd);
rcu_read_lock();
vcc = rcu_dereference(priv->lecd);
if (!vcc) {
rcu_read_unlock();
kfree_skb(skb);
return -1;
}
atm_force_charge(vcc, skb->truesize);
sk = sk_atm(vcc);
skb_queue_tail(&sk->sk_receive_queue, skb);
sk->sk_data_ready(sk);
if (data != NULL) {
pr_debug("about to send %d bytes of data\n", data->len);
atm_force_charge(priv->lecd, data->truesize);
atm_force_charge(vcc, data->truesize);
skb_queue_tail(&sk->sk_receive_queue, data);
sk->sk_data_ready(sk);
}
rcu_read_unlock();
return 0;
}
@@ -618,7 +640,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
atm_return(vcc, skb->truesize);
if (*(__be16 *) skb->data == htons(priv->lecid) ||
!priv->lecd || !(dev->flags & IFF_UP)) {
!rcu_access_pointer(priv->lecd) || !(dev->flags & IFF_UP)) {
/*
* Probably looping back, or if lecd is missing,
* lecd has gone down
@@ -753,12 +775,12 @@ static int lecd_attach(struct atm_vcc *vcc, int arg)
priv = netdev_priv(dev_lec[i]);
} else {
priv = netdev_priv(dev_lec[i]);
if (priv->lecd)
if (rcu_access_pointer(priv->lecd))
return -EADDRINUSE;
}
lec_arp_init(priv);
priv->itfnum = i; /* LANE2 addition */
priv->lecd = vcc;
rcu_assign_pointer(priv->lecd, vcc);
vcc->dev = &lecatm_dev;
vcc_insert_socket(sk_atm(vcc));

View File

@@ -91,7 +91,7 @@ struct lec_priv {
*/
spinlock_t lec_arp_lock;
struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */
struct atm_vcc *lecd;
struct atm_vcc __rcu *lecd;
struct delayed_work lec_arp_work; /* C10 */
unsigned int maximum_unknown_frame_count;
/*

View File

@@ -473,6 +473,9 @@ batadv_iv_ogm_can_aggregate(const struct batadv_ogm_packet *new_bat_ogm_packet,
if (aggregated_bytes > max_bytes)
return false;
if (skb_tailroom(forw_packet->skb) < packet_len)
return false;
if (packet_num >= BATADV_MAX_AGGREGATION_PACKETS)
return false;

View File

@@ -1944,6 +1944,8 @@ static bool hci_le_set_cig_params(struct hci_conn *conn, struct bt_iso_qos *qos)
return false;
done:
conn->iso_qos = *qos;
if (hci_cmd_sync_queue(hdev, set_cig_params_sync,
UINT_PTR(qos->ucast.cig), NULL) < 0)
return false;
@@ -2013,8 +2015,6 @@ struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst,
}
hci_conn_hold(cis);
cis->iso_qos = *qos;
cis->state = BT_BOUND;
return cis;

View File

@@ -6627,8 +6627,8 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)
* state.
*/
if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
hci_scan_disable_sync(hdev);
hci_dev_set_flag(hdev, HCI_LE_SCAN_INTERRUPTED);
hci_scan_disable_sync(hdev);
}
/* Update random address, but set require_privacy to false so

View File

@@ -986,6 +986,7 @@ static void session_free(struct kref *ref)
skb_queue_purge(&session->intr_transmit);
fput(session->intr_sock->file);
fput(session->ctrl_sock->file);
if (session->conn)
l2cap_conn_put(session->conn);
kfree(session);
}
@@ -1164,6 +1165,15 @@ static void hidp_session_remove(struct l2cap_conn *conn,
down_write(&hidp_session_sem);
/* Drop L2CAP reference immediately to indicate that
* l2cap_unregister_user() shall not be called as it is already
* considered removed.
*/
if (session->conn) {
l2cap_conn_put(session->conn);
session->conn = NULL;
}
hidp_session_terminate(session);
cancel_work_sync(&session->dev_init);
@@ -1301,7 +1311,9 @@ static int hidp_session_thread(void *arg)
* Instead, this call has the same semantics as if user-space tried to
* delete the session.
*/
if (session->conn)
l2cap_unregister_user(session->conn, &session->user);
hidp_session_put(session);
module_put_and_kthread_exit(0);

View File

@@ -1678,17 +1678,15 @@ static void l2cap_info_timeout(struct work_struct *work)
int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user)
{
struct hci_dev *hdev = conn->hcon->hdev;
int ret;
/* We need to check whether l2cap_conn is registered. If it is not, we
* must not register the l2cap_user. l2cap_conn_del() is unregisters
* l2cap_conn objects, but doesn't provide its own locking. Instead, it
* relies on the parent hci_conn object to be locked. This itself relies
* on the hci_dev object to be locked. So we must lock the hci device
* here, too. */
* must not register the l2cap_user. l2cap_conn_del() unregisters
* l2cap_conn objects under conn->lock, and we use the same lock here
* to protect access to conn->users and conn->hchan.
*/
hci_dev_lock(hdev);
mutex_lock(&conn->lock);
if (!list_empty(&user->list)) {
ret = -EINVAL;
@@ -1709,16 +1707,14 @@ int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user)
ret = 0;
out_unlock:
hci_dev_unlock(hdev);
mutex_unlock(&conn->lock);
return ret;
}
EXPORT_SYMBOL(l2cap_register_user);
void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user)
{
struct hci_dev *hdev = conn->hcon->hdev;
hci_dev_lock(hdev);
mutex_lock(&conn->lock);
if (list_empty(&user->list))
goto out_unlock;
@@ -1727,7 +1723,7 @@ void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user)
user->remove(conn, user);
out_unlock:
hci_dev_unlock(hdev);
mutex_unlock(&conn->lock);
}
EXPORT_SYMBOL(l2cap_unregister_user);
@@ -4616,6 +4612,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn,
switch (type) {
case L2CAP_IT_FEAT_MASK:
if (cmd_len >= sizeof(*rsp) + sizeof(u32))
conn->feat_mask = get_unaligned_le32(rsp->data);
if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
@@ -4635,6 +4632,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn,
break;
case L2CAP_IT_FIXED_CHAN:
if (cmd_len >= sizeof(*rsp) + sizeof(rsp->data[0]))
conn->remote_fixed_chan = rsp->data[0];
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
conn->info_ident = 0;
@@ -5059,7 +5057,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
u16 mtu, mps;
__le16 psm;
u8 result, rsp_len = 0;
int i, num_scid;
int i, num_scid = 0;
bool defer = false;
if (!enable_ecred)
@@ -5072,6 +5070,14 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
goto response;
}
/* Check if there are no pending channels with the same ident */
__l2cap_chan_list_id(conn, cmd->ident, l2cap_ecred_list_defer,
&num_scid);
if (num_scid) {
result = L2CAP_CR_LE_INVALID_PARAMS;
goto response;
}
cmd_len -= sizeof(*req);
num_scid = cmd_len / sizeof(u16);
@@ -5424,7 +5430,7 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn,
u8 *data)
{
struct l2cap_chan *chan, *tmp;
struct l2cap_ecred_conn_rsp *rsp = (void *) data;
struct l2cap_ecred_reconf_rsp *rsp = (void *)data;
u16 result;
if (cmd_len < sizeof(*rsp))
@@ -5432,7 +5438,7 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn,
result = __le16_to_cpu(rsp->result);
BT_DBG("result 0x%4.4x", rsp->result);
BT_DBG("result 0x%4.4x", result);
if (!result)
return 0;
@@ -6662,8 +6668,10 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
return -ENOBUFS;
}
if (chan->imtu < skb->len) {
BT_ERR("Too big LE L2CAP PDU");
if (skb->len > chan->imtu) {
BT_ERR("Too big LE L2CAP PDU: len %u > %u", skb->len,
chan->imtu);
l2cap_send_disconn_req(chan, ECONNRESET);
return -ENOBUFS;
}
@@ -6689,7 +6697,9 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
sdu_len, skb->len, chan->imtu);
if (sdu_len > chan->imtu) {
BT_ERR("Too big LE L2CAP SDU length received");
BT_ERR("Too big LE L2CAP SDU length: len %u > %u",
skb->len, sdu_len);
l2cap_send_disconn_req(chan, ECONNRESET);
err = -EMSGSIZE;
goto failed;
}
@@ -6725,6 +6735,7 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
if (chan->sdu->len + skb->len > chan->sdu_len) {
BT_ERR("Too much LE L2CAP data received");
l2cap_send_disconn_req(chan, ECONNRESET);
err = -EINVAL;
goto failed;
}

View File

@@ -2195,10 +2195,7 @@ static void set_mesh_complete(struct hci_dev *hdev, void *data, int err)
sk = cmd->sk;
if (status) {
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);
mgmt_cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
goto done;
}
@@ -5377,7 +5374,7 @@ static void mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev,
mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
mgmt_status(status), &rp, sizeof(rp));
mgmt_pending_remove(cmd);
mgmt_pending_free(cmd);
hci_dev_unlock(hdev);
bt_dev_dbg(hdev, "add monitor %d complete, status %d",

View File

@@ -2743,7 +2743,7 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
if (!test_bit(SMP_FLAG_DEBUG_KEY, &smp->flags) &&
!crypto_memneq(key, smp->local_pk, 64)) {
bt_dev_err(hdev, "Remote and local public keys are identical");
return SMP_UNSPECIFIED;
return SMP_DHKEY_CHECK_FAILED;
}
memcpy(smp->remote_pk, key, 64);

View File

@@ -576,7 +576,7 @@ static void mep_delete_implementation(struct net_bridge *br,
/* Empty and free peer MEP list */
hlist_for_each_entry_safe(peer_mep, n_store, &mep->peer_mep_list, head) {
cancel_delayed_work_sync(&peer_mep->ccm_rx_dwork);
disable_delayed_work_sync(&peer_mep->ccm_rx_dwork);
hlist_del_rcu(&peer_mep->head);
kfree_rcu(peer_mep, rcu);
}
@@ -732,7 +732,7 @@ int br_cfm_cc_peer_mep_remove(struct net_bridge *br, const u32 instance,
return -ENOENT;
}
cc_peer_disable(peer_mep);
disable_delayed_work_sync(&peer_mep->ccm_rx_dwork);
hlist_del_rcu(&peer_mep->head);
kfree_rcu(peer_mep, rcu);

View File

@@ -193,14 +193,11 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
}
EXPORT_SYMBOL(eth_type_trans);
/**
* eth_header_parse - extract hardware address from packet
* @skb: packet to extract header from
* @haddr: destination buffer
*/
int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr)
int eth_header_parse(const struct sk_buff *skb, const struct net_device *dev,
unsigned char *haddr)
{
const struct ethhdr *eth = eth_hdr(skb);
memcpy(haddr, eth->h_source, ETH_ALEN);
return ETH_ALEN;
}

View File

@@ -1079,10 +1079,12 @@ out:
static bool icmp_tag_validation(int proto)
{
const struct net_protocol *ipprot;
bool ok;
rcu_read_lock();
ok = rcu_dereference(inet_protos[proto])->icmp_strict_tag_validation;
ipprot = rcu_dereference(inet_protos[proto]);
ok = ipprot ? ipprot->icmp_strict_tag_validation : false;
rcu_read_unlock();
return ok;
}

View File

@@ -919,7 +919,8 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
return -(t->hlen + sizeof(*iph));
}
static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr)
static int ipgre_header_parse(const struct sk_buff *skb, const struct net_device *dev,
unsigned char *haddr)
{
const struct iphdr *iph = (const struct iphdr *) skb_mac_header(skb);
memcpy(haddr, &iph->saddr, 4);

View File

@@ -379,6 +379,10 @@ static int ipv6_srh_rcv(struct sk_buff *skb)
hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);
idev = __in6_dev_get(skb->dev);
if (!idev) {
kfree_skb(skb);
return -1;
}
accept_seg6 = min(READ_ONCE(net->ipv6.devconf_all->seg6_enabled),
READ_ONCE(idev->cnf.seg6_enabled));

View File

@@ -184,6 +184,8 @@ bool seg6_hmac_validate_skb(struct sk_buff *skb)
int require_hmac;
idev = __in6_dev_get(skb->dev);
if (!idev)
return false;
srh = (struct ipv6_sr_hdr *)skb_transport_header(skb);

View File

@@ -1904,12 +1904,6 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev,
__sta_info_flush(sdata, true, link_id, NULL);
ieee80211_remove_link_keys(link, &keys);
if (!list_empty(&keys)) {
synchronize_net();
ieee80211_free_key_list(local, &keys);
}
ieee80211_stop_mbssid(sdata);
RCU_INIT_POINTER(link_conf->tx_bss_conf, NULL);
@@ -1921,6 +1915,12 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev,
ieee80211_link_info_change_notify(sdata, link,
BSS_CHANGED_BEACON_ENABLED);
ieee80211_remove_link_keys(link, &keys);
if (!list_empty(&keys)) {
synchronize_net();
ieee80211_free_key_list(local, &keys);
}
if (sdata->wdev.links[link_id].cac_started) {
chandef = link_conf->chanreq.oper;
wiphy_hrtimer_work_cancel(wiphy, &link->dfs_cac_timer_work);

View File

@@ -561,14 +561,16 @@ static void ieee80211_chan_bw_change(struct ieee80211_local *local,
rcu_read_lock();
list_for_each_entry_rcu(sta, &local->sta_list,
list) {
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_sub_if_data *sdata;
enum ieee80211_sta_rx_bandwidth new_sta_bw;
unsigned int link_id;
if (!ieee80211_sdata_running(sta->sdata))
continue;
for (link_id = 0; link_id < ARRAY_SIZE(sta->sdata->link); link_id++) {
sdata = get_bss_sdata(sta->sdata);
for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
struct ieee80211_link_data *link =
rcu_dereference(sdata->link[link_id]);
struct ieee80211_bss_conf *link_conf;

View File

@@ -320,7 +320,6 @@ static ssize_t aql_enable_read(struct file *file, char __user *user_buf,
static ssize_t aql_enable_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
bool aql_disabled = static_key_false(&aql_disable.key);
char buf[3];
size_t len;
@@ -335,15 +334,12 @@ static ssize_t aql_enable_write(struct file *file, const char __user *user_buf,
if (len > 0 && buf[len - 1] == '\n')
buf[len - 1] = 0;
if (buf[0] == '0' && buf[1] == '\0') {
if (!aql_disabled)
static_branch_inc(&aql_disable);
} else if (buf[0] == '1' && buf[1] == '\0') {
if (aql_disabled)
static_branch_dec(&aql_disable);
} else {
if (buf[0] == '0' && buf[1] == '\0')
static_branch_enable(&aql_disable);
else if (buf[0] == '1' && buf[1] == '\0')
static_branch_disable(&aql_disable);
else
return -EINVAL;
}
return count;
}

View File

@@ -79,6 +79,9 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
* - MDA enabled
* - Power management control on fc
*/
if (!ie->mesh_config)
return false;
if (!(ifmsh->mesh_id_len == ie->mesh_id_len &&
memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
(ifmsh->mesh_pp_id == ie->mesh_config->meshconf_psel) &&

View File

@@ -2782,7 +2782,9 @@ static void sta_set_link_sinfo(struct sta_info *sta,
}
link_sinfo->inactive_time =
jiffies_to_msecs(jiffies - ieee80211_sta_last_active(sta, link_id));
jiffies_delta_to_msecs(jiffies -
ieee80211_sta_last_active(sta,
link_id));
if (!(link_sinfo->filled & (BIT_ULL(NL80211_STA_INFO_TX_BYTES64) |
BIT_ULL(NL80211_STA_INFO_TX_BYTES)))) {
@@ -3015,7 +3017,8 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
sinfo->connected_time = ktime_get_seconds() - sta->last_connected;
sinfo->assoc_at = sta->assoc_at;
sinfo->inactive_time =
jiffies_to_msecs(jiffies - ieee80211_sta_last_active(sta, -1));
jiffies_delta_to_msecs(jiffies -
ieee80211_sta_last_active(sta, -1));
if (!(sinfo->filled & (BIT_ULL(NL80211_STA_INFO_TX_BYTES64) |
BIT_ULL(NL80211_STA_INFO_TX_BYTES)))) {

View File

@@ -1449,7 +1449,7 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
}
sta = sta_info_get(sdata, peer);
if (!sta)
if (!sta || !sta->sta.tdls)
return -ENOLINK;
iee80211_tdls_recalc_chanctx(sdata, sta);

View File

@@ -1899,8 +1899,10 @@ bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
struct ieee80211_tx_data tx;
struct sk_buff *skb2;
if (ieee80211_tx_prepare(sdata, &tx, NULL, skb) == TX_DROP)
if (ieee80211_tx_prepare(sdata, &tx, NULL, skb) == TX_DROP) {
kfree_skb(skb);
return false;
}
info->band = band;
info->control.vif = vif;

View File

@@ -469,7 +469,9 @@ static int mac802154_header_create(struct sk_buff *skb,
}
static int
mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr)
mac802154_header_parse(const struct sk_buff *skb,
const struct net_device *dev,
unsigned char *haddr)
{
struct ieee802154_hdr hdr;

View File

@@ -2854,6 +2854,7 @@ out_unregister_rtnl_af:
rtnl_af_unregister(&mpls_af_ops);
out_unregister_dev_type:
dev_remove_pack(&mpls_packet_type);
unregister_netdevice_notifier(&mpls_dev_notifier);
out_unregister_pernet:
unregister_pernet_subsys(&mpls_net_ops);
goto out;

View File

@@ -838,7 +838,7 @@ static struct lock_class_key mptcp_keys[2];
static int mptcp_pm_nl_create_listen_socket(struct sock *sk,
struct mptcp_pm_addr_entry *entry)
{
bool is_ipv6 = sk->sk_family == AF_INET6;
bool is_ipv6 = entry->addr.family == AF_INET6;
int addrlen = sizeof(struct sockaddr_in);
struct sockaddr_storage addr;
struct sock *newsk, *ssk;

View File

@@ -170,7 +170,7 @@ static int bpf_nf_link_update(struct bpf_link *link, struct bpf_prog *new_prog,
static const struct bpf_link_ops bpf_nf_link_lops = {
.release = bpf_nf_link_release,
.dealloc = bpf_nf_link_dealloc,
.dealloc_deferred = bpf_nf_link_dealloc,
.detach = bpf_nf_link_detach,
.show_fdinfo = bpf_nf_link_show_info,
.fill_link_info = bpf_nf_link_fill_link_info,

View File

@@ -331,6 +331,8 @@ static int decode_int(struct bitstr *bs, const struct field_t *f,
if (nf_h323_error_boundary(bs, 0, 2))
return H323_ERROR_BOUND;
len = get_bits(bs, 2) + 1;
if (nf_h323_error_boundary(bs, len, 0))
return H323_ERROR_BOUND;
BYTE_ALIGN(bs);
if (base && (f->attr & DECODE)) { /* timeToLive */
unsigned int v = get_uint(bs, len) + f->lb;
@@ -922,6 +924,8 @@ int DecodeQ931(unsigned char *buf, size_t sz, Q931 *q931)
break;
p++;
len--;
if (len <= 0)
break;
return DecodeH323_UserInformation(buf, p, len,
&q931->UUIE);
}

View File

@@ -3212,7 +3212,7 @@ ctnetlink_exp_ct_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
{
struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
struct nf_conn *ct = cb->data;
struct nf_conn_help *help = nfct_help(ct);
struct nf_conn_help *help;
u_int8_t l3proto = nfmsg->nfgen_family;
unsigned long last_id = cb->args[1];
struct nf_conntrack_expect *exp;
@@ -3220,6 +3220,10 @@ ctnetlink_exp_ct_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
if (cb->args[0])
return 0;
help = nfct_help(ct);
if (!help)
return 0;
rcu_read_lock();
restart:
@@ -3249,6 +3253,24 @@ out:
return skb->len;
}
static int ctnetlink_dump_exp_ct_start(struct netlink_callback *cb)
{
struct nf_conn *ct = cb->data;
if (!refcount_inc_not_zero(&ct->ct_general.use))
return -ENOENT;
return 0;
}
static int ctnetlink_dump_exp_ct_done(struct netlink_callback *cb)
{
struct nf_conn *ct = cb->data;
if (ct)
nf_ct_put(ct);
return 0;
}
static int ctnetlink_dump_exp_ct(struct net *net, struct sock *ctnl,
struct sk_buff *skb,
const struct nlmsghdr *nlh,
@@ -3264,6 +3286,8 @@ static int ctnetlink_dump_exp_ct(struct net *net, struct sock *ctnl,
struct nf_conntrack_zone zone;
struct netlink_dump_control c = {
.dump = ctnetlink_exp_ct_dump_table,
.start = ctnetlink_dump_exp_ct_start,
.done = ctnetlink_dump_exp_ct_done,
};
err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER,
@@ -3465,7 +3489,7 @@ ctnetlink_change_expect(struct nf_conntrack_expect *x,
#if IS_ENABLED(CONFIG_NF_NAT)
static const struct nla_policy exp_nat_nla_policy[CTA_EXPECT_NAT_MAX+1] = {
[CTA_EXPECT_NAT_DIR] = { .type = NLA_U32 },
[CTA_EXPECT_NAT_DIR] = NLA_POLICY_MAX(NLA_BE32, IP_CT_DIR_REPLY),
[CTA_EXPECT_NAT_TUPLE] = { .type = NLA_NESTED },
};
#endif

View File

@@ -582,7 +582,8 @@ nla_put_failure:
}
static const struct nla_policy sctp_nla_policy[CTA_PROTOINFO_SCTP_MAX+1] = {
[CTA_PROTOINFO_SCTP_STATE] = { .type = NLA_U8 },
[CTA_PROTOINFO_SCTP_STATE] = NLA_POLICY_MAX(NLA_U8,
SCTP_CONNTRACK_HEARTBEAT_SENT),
[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL] = { .type = NLA_U32 },
[CTA_PROTOINFO_SCTP_VTAG_REPLY] = { .type = NLA_U32 },
};

View File

@@ -1534,11 +1534,12 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,
{
struct tcphdr *th, _tcph;
unsigned int dataoff, datalen;
unsigned int matchoff, matchlen, clen;
unsigned int matchoff, matchlen;
unsigned int msglen, origlen;
const char *dptr, *end;
s16 diff, tdiff = 0;
int ret = NF_ACCEPT;
unsigned long clen;
bool term;
if (ctinfo != IP_CT_ESTABLISHED &&
@@ -1573,6 +1574,9 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,
if (dptr + matchoff == end)
break;
if (clen > datalen)
break;
term = false;
for (; end + strlen("\r\n\r\n") <= dptr + datalen; end++) {
if (end[0] == '\r' && end[1] == '\n' &&

View File

@@ -738,6 +738,7 @@ static int nf_flow_encap_push(struct sk_buff *skb,
switch (tuple->encap[i].proto) {
case htons(ETH_P_8021Q):
case htons(ETH_P_8021AD):
skb_reset_mac_header(skb);
if (skb_vlan_push(skb, tuple->encap[i].proto,
tuple->encap[i].id) < 0)
return -1;

View File

@@ -6744,7 +6744,7 @@ static void __nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
}
}
static void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
struct nft_set_elem_expr *elem_expr)
{
struct nft_expr *expr;
@@ -7156,8 +7156,7 @@ static u32 nft_set_maxsize(const struct nft_set *set)
}
static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
const struct nlattr *attr, u32 nlmsg_flags,
bool last)
const struct nlattr *attr, u32 nlmsg_flags)
{
struct nft_expr *expr_array[NFT_SET_EXPR_MAX] = {};
struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
@@ -7444,11 +7443,6 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
if (flags)
*nft_set_ext_flags(ext) = flags;
if (last)
elem.flags = NFT_SET_ELEM_INTERNAL_LAST;
else
elem.flags = 0;
if (obj)
*nft_set_ext_obj(ext) = obj;
@@ -7613,8 +7607,7 @@ static int nf_tables_newsetelem(struct sk_buff *skb,
nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
err = nft_add_set_elem(&ctx, set, attr, info->nlh->nlmsg_flags,
nla_is_last(attr, rem));
err = nft_add_set_elem(&ctx, set, attr, info->nlh->nlmsg_flags);
if (err < 0) {
NL_SET_BAD_ATTR(extack, attr);
return err;
@@ -7738,7 +7731,7 @@ static void nft_trans_elems_destroy_abort(const struct nft_ctx *ctx,
}
static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
const struct nlattr *attr, bool last)
const struct nlattr *attr)
{
struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
struct nft_set_ext_tmpl tmpl;
@@ -7806,11 +7799,6 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
if (flags)
*nft_set_ext_flags(ext) = flags;
if (last)
elem.flags = NFT_SET_ELEM_INTERNAL_LAST;
else
elem.flags = 0;
trans = nft_trans_elem_alloc(ctx, NFT_MSG_DELSETELEM, set);
if (trans == NULL)
goto fail_trans;
@@ -7961,8 +7949,7 @@ static int nf_tables_delsetelem(struct sk_buff *skb,
return nft_set_flush(&ctx, set, genmask);
nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
err = nft_del_setelem(&ctx, set, attr,
nla_is_last(attr, rem));
err = nft_del_setelem(&ctx, set, attr);
if (err == -ENOENT &&
NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYSETELEM)
continue;
@@ -9216,6 +9203,7 @@ static int nf_tables_newflowtable(struct sk_buff *skb,
return 0;
err_flowtable_hooks:
synchronize_rcu();
nft_trans_destroy(trans);
err_flowtable_trans:
nft_hooks_destroy(&flowtable->hook_list);

View File

@@ -302,7 +302,9 @@ static int nfnl_osf_add_callback(struct sk_buff *skb,
{
struct nf_osf_user_finger *f;
struct nf_osf_finger *kf = NULL, *sf;
unsigned int tot_opt_len = 0;
int err = 0;
int i;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -318,6 +320,17 @@ static int nfnl_osf_add_callback(struct sk_buff *skb,
if (f->opt_num > ARRAY_SIZE(f->opt))
return -EINVAL;
for (i = 0; i < f->opt_num; i++) {
if (!f->opt[i].length || f->opt[i].length > MAX_IPOPTLEN)
return -EINVAL;
if (f->opt[i].kind == OSFOPT_MSS && f->opt[i].length < 4)
return -EINVAL;
tot_opt_len += f->opt[i].length;
if (tot_opt_len > MAX_IPOPTLEN)
return -EINVAL;
}
if (!memchr(f->genre, 0, MAXGENRELEN) ||
!memchr(f->subtype, 0, MAXGENRELEN) ||
!memchr(f->version, 0, MAXGENRELEN))

View File

@@ -23,6 +23,7 @@
#include <net/netfilter/nf_conntrack_l4proto.h>
#include <net/netfilter/nf_conntrack_expect.h>
#include <net/netfilter/nf_conntrack_seqadj.h>
#include "nf_internals.h"
struct nft_ct_helper_obj {
struct nf_conntrack_helper *helper4;
@@ -543,6 +544,7 @@ static void __nft_ct_set_destroy(const struct nft_ctx *ctx, struct nft_ct *priv)
#endif
#ifdef CONFIG_NF_CONNTRACK_ZONES
case NFT_CT_ZONE:
nf_queue_nf_hook_drop(ctx->net);
mutex_lock(&nft_ct_pcpu_mutex);
if (--nft_ct_pcpu_template_refcnt == 0)
nft_ct_tmpl_put_pcpu();
@@ -1015,6 +1017,7 @@ static void nft_ct_timeout_obj_destroy(const struct nft_ctx *ctx,
struct nft_ct_timeout_obj *priv = nft_obj_data(obj);
struct nf_ct_timeout *timeout = priv->timeout;
nf_queue_nf_hook_drop(ctx->net);
nf_ct_untimeout(ctx->net, timeout);
nf_ct_netns_put(ctx->net, ctx->family);
kfree(priv->timeout);
@@ -1147,6 +1150,7 @@ static void nft_ct_helper_obj_destroy(const struct nft_ctx *ctx,
{
struct nft_ct_helper_obj *priv = nft_obj_data(obj);
nf_queue_nf_hook_drop(ctx->net);
if (priv->helper4)
nf_conntrack_helper_put(priv->helper4);
if (priv->helper6)

View File

@@ -30,18 +30,26 @@ static int nft_dynset_expr_setup(const struct nft_dynset *priv,
const struct nft_set_ext *ext)
{
struct nft_set_elem_expr *elem_expr = nft_set_ext_expr(ext);
struct nft_ctx ctx = {
.net = read_pnet(&priv->set->net),
.family = priv->set->table->family,
};
struct nft_expr *expr;
int i;
for (i = 0; i < priv->num_exprs; i++) {
expr = nft_setelem_expr_at(elem_expr, elem_expr->size);
if (nft_expr_clone(expr, priv->expr_array[i], GFP_ATOMIC) < 0)
return -1;
goto err_out;
elem_expr->size += priv->expr_array[i]->ops->size;
}
return 0;
err_out:
nft_set_elem_expr_destroy(&ctx, elem_expr);
return -1;
}
struct nft_elem_priv *nft_dynset_new(struct nft_set *set,

View File

@@ -304,19 +304,10 @@ static void nft_rbtree_set_start_cookie(struct nft_rbtree *priv,
priv->start_rbe_cookie = (unsigned long)rbe;
}
static void nft_rbtree_set_start_cookie_open(struct nft_rbtree *priv,
const struct nft_rbtree_elem *rbe,
unsigned long open_interval)
{
priv->start_rbe_cookie = (unsigned long)rbe | open_interval;
}
#define NFT_RBTREE_OPEN_INTERVAL 1UL
static bool nft_rbtree_cmp_start_cookie(struct nft_rbtree *priv,
const struct nft_rbtree_elem *rbe)
{
return (priv->start_rbe_cookie & ~NFT_RBTREE_OPEN_INTERVAL) == (unsigned long)rbe;
return priv->start_rbe_cookie == (unsigned long)rbe;
}
static bool nft_rbtree_insert_same_interval(const struct net *net,
@@ -346,14 +337,13 @@ static bool nft_rbtree_insert_same_interval(const struct net *net,
static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
struct nft_rbtree_elem *new,
struct nft_elem_priv **elem_priv, u64 tstamp, bool last)
struct nft_elem_priv **elem_priv, u64 tstamp)
{
struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL, *rbe_prev;
struct rb_node *node, *next, *parent, **p, *first = NULL;
struct nft_rbtree *priv = nft_set_priv(set);
u8 cur_genmask = nft_genmask_cur(net);
u8 genmask = nft_genmask_next(net);
unsigned long open_interval = 0;
int d;
/* Descend the tree to search for an existing element greater than the
@@ -459,18 +449,10 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
}
}
if (nft_rbtree_interval_null(set, new)) {
if (nft_rbtree_interval_null(set, new))
priv->start_rbe_cookie = 0;
} else if (nft_rbtree_interval_start(new) && priv->start_rbe_cookie) {
if (nft_set_is_anonymous(set)) {
else if (nft_rbtree_interval_start(new) && priv->start_rbe_cookie)
priv->start_rbe_cookie = 0;
} else if (priv->start_rbe_cookie & NFT_RBTREE_OPEN_INTERVAL) {
/* Previous element is an open interval that partially
* overlaps with an existing non-open interval.
*/
return -ENOTEMPTY;
}
}
/* - new start element matching existing start element: full overlap
* reported as -EEXIST, cleared by caller if NLM_F_EXCL is not given.
@@ -478,27 +460,7 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
if (rbe_ge && !nft_rbtree_cmp(set, new, rbe_ge) &&
nft_rbtree_interval_start(rbe_ge) == nft_rbtree_interval_start(new)) {
*elem_priv = &rbe_ge->priv;
/* - Corner case: new start element of open interval (which
* comes as last element in the batch) overlaps the start of
* an existing interval with an end element: partial overlap.
*/
node = rb_first(&priv->root);
rbe = __nft_rbtree_next_active(node, genmask);
if (rbe && nft_rbtree_interval_end(rbe)) {
rbe = nft_rbtree_next_active(rbe, genmask);
if (rbe &&
nft_rbtree_interval_start(rbe) &&
!nft_rbtree_cmp(set, new, rbe)) {
if (last)
return -ENOTEMPTY;
/* Maybe open interval? */
open_interval = NFT_RBTREE_OPEN_INTERVAL;
}
}
nft_rbtree_set_start_cookie_open(priv, rbe_ge, open_interval);
nft_rbtree_set_start_cookie(priv, rbe_ge);
return -EEXIST;
}
@@ -553,12 +515,6 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
nft_rbtree_interval_end(rbe_ge) && nft_rbtree_interval_end(new))
return -ENOTEMPTY;
/* - start element overlaps an open interval but end element is new:
* partial overlap, reported as -ENOEMPTY.
*/
if (!rbe_ge && priv->start_rbe_cookie && nft_rbtree_interval_end(new))
return -ENOTEMPTY;
/* Accepted element: pick insertion point depending on key value */
parent = NULL;
p = &priv->root.rb_node;
@@ -668,7 +624,6 @@ static int nft_rbtree_insert(const struct net *net, const struct nft_set *set,
struct nft_elem_priv **elem_priv)
{
struct nft_rbtree_elem *rbe = nft_elem_priv_cast(elem->priv);
bool last = !!(elem->flags & NFT_SET_ELEM_INTERNAL_LAST);
struct nft_rbtree *priv = nft_set_priv(set);
u64 tstamp = nft_net_tstamp(net);
int err;
@@ -685,12 +640,8 @@ static int nft_rbtree_insert(const struct net *net, const struct nft_set *set,
cond_resched();
write_lock_bh(&priv->lock);
err = __nft_rbtree_insert(net, set, rbe, elem_priv, tstamp, last);
err = __nft_rbtree_insert(net, set, rbe, elem_priv, tstamp);
write_unlock_bh(&priv->lock);
if (nft_rbtree_interval_end(rbe))
priv->start_rbe_cookie = 0;
} while (err == -EAGAIN);
return err;
@@ -778,7 +729,6 @@ nft_rbtree_deactivate(const struct net *net, const struct nft_set *set,
const struct nft_set_elem *elem)
{
struct nft_rbtree_elem *rbe, *this = nft_elem_priv_cast(elem->priv);
bool last = !!(elem->flags & NFT_SET_ELEM_INTERNAL_LAST);
struct nft_rbtree *priv = nft_set_priv(set);
const struct rb_node *parent = priv->root.rb_node;
u8 genmask = nft_genmask_next(net);
@@ -819,10 +769,9 @@ nft_rbtree_deactivate(const struct net *net, const struct nft_set *set,
continue;
}
if (nft_rbtree_interval_start(rbe)) {
if (!last)
if (nft_rbtree_interval_start(rbe))
nft_rbtree_set_start_cookie(priv, rbe);
} else if (!nft_rbtree_deactivate_same_interval(net, priv, rbe))
else if (!nft_rbtree_deactivate_same_interval(net, priv, rbe))
return NULL;
nft_rbtree_flush(net, set, &rbe->priv);

View File

@@ -16,6 +16,7 @@
#include <net/netfilter/nf_conntrack_ecache.h>
#include <net/netfilter/nf_conntrack_timeout.h>
#include <net/netfilter/nf_conntrack_zones.h>
#include "nf_internals.h"
static inline int xt_ct_target(struct sk_buff *skb, struct nf_conn *ct)
{
@@ -283,6 +284,9 @@ static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par,
struct nf_conn_help *help;
if (ct) {
if (info->helper[0] || info->timeout[0])
nf_queue_nf_hook_drop(par->net);
help = nfct_help(ct);
xt_ct_put_helper(help);

View File

@@ -223,13 +223,13 @@ time_mt(const struct sk_buff *skb, struct xt_action_param *par)
localtime_2(&current_time, stamp);
if (!(info->weekdays_match & (1 << current_time.weekday)))
if (!(info->weekdays_match & (1U << current_time.weekday)))
return false;
/* Do not spend time computing monthday if all days match anyway */
if (info->monthdays_match != XT_TIME_ALL_MONTHDAYS) {
localtime_3(&current_time, stamp);
if (!(info->monthdays_match & (1 << current_time.monthday)))
if (!(info->monthdays_match & (1U << current_time.monthday)))
return false;
}

View File

@@ -129,9 +129,12 @@ static int pn_header_create(struct sk_buff *skb, struct net_device *dev,
return 1;
}
static int pn_header_parse(const struct sk_buff *skb, unsigned char *haddr)
static int pn_header_parse(const struct sk_buff *skb,
const struct net_device *dev,
unsigned char *haddr)
{
const u8 *media = skb_mac_header(skb);
*haddr = *media;
return 1;
}

View File

@@ -811,6 +811,11 @@ static int rose_connect(struct socket *sock, struct sockaddr_unsized *uaddr, int
goto out_release;
}
if (sk->sk_state == TCP_SYN_SENT) {
err = -EALREADY;
goto out_release;
}
sk->sk_state = TCP_CLOSE;
sock->state = SS_UNCONNECTED;

View File

@@ -1288,33 +1288,6 @@ static void dev_deactivate_queue(struct net_device *dev,
}
}
static void dev_reset_queue(struct net_device *dev,
struct netdev_queue *dev_queue,
void *_unused)
{
struct Qdisc *qdisc;
bool nolock;
qdisc = rtnl_dereference(dev_queue->qdisc_sleeping);
if (!qdisc)
return;
nolock = qdisc->flags & TCQ_F_NOLOCK;
if (nolock)
spin_lock_bh(&qdisc->seqlock);
spin_lock_bh(qdisc_lock(qdisc));
qdisc_reset(qdisc);
spin_unlock_bh(qdisc_lock(qdisc));
if (nolock) {
clear_bit(__QDISC_STATE_MISSED, &qdisc->state);
clear_bit(__QDISC_STATE_DRAINING, &qdisc->state);
spin_unlock_bh(&qdisc->seqlock);
}
}
static bool some_qdisc_is_busy(struct net_device *dev)
{
unsigned int i;

View File

@@ -113,14 +113,15 @@ static void ingress_destroy(struct Qdisc *sch)
{
struct ingress_sched_data *q = qdisc_priv(sch);
struct net_device *dev = qdisc_dev(sch);
struct bpf_mprog_entry *entry = rtnl_dereference(dev->tcx_ingress);
struct bpf_mprog_entry *entry;
if (sch->parent != TC_H_INGRESS)
return;
tcf_block_put_ext(q->block, sch, &q->block_info);
if (entry) {
if (mini_qdisc_pair_inited(&q->miniqp)) {
entry = rtnl_dereference(dev->tcx_ingress);
tcx_miniq_dec(entry);
if (!tcx_entry_is_active(entry)) {
tcx_entry_update(dev, NULL, true);
@@ -290,10 +291,9 @@ static int clsact_init(struct Qdisc *sch, struct nlattr *opt,
static void clsact_destroy(struct Qdisc *sch)
{
struct bpf_mprog_entry *ingress_entry, *egress_entry;
struct clsact_sched_data *q = qdisc_priv(sch);
struct net_device *dev = qdisc_dev(sch);
struct bpf_mprog_entry *ingress_entry = rtnl_dereference(dev->tcx_ingress);
struct bpf_mprog_entry *egress_entry = rtnl_dereference(dev->tcx_egress);
if (sch->parent != TC_H_CLSACT)
return;
@@ -301,7 +301,8 @@ static void clsact_destroy(struct Qdisc *sch)
tcf_block_put_ext(q->ingress_block, sch, &q->ingress_block_info);
tcf_block_put_ext(q->egress_block, sch, &q->egress_block_info);
if (ingress_entry) {
if (mini_qdisc_pair_inited(&q->miniqp_ingress)) {
ingress_entry = rtnl_dereference(dev->tcx_ingress);
tcx_miniq_dec(ingress_entry);
if (!tcx_entry_is_active(ingress_entry)) {
tcx_entry_update(dev, NULL, true);
@@ -309,7 +310,8 @@ static void clsact_destroy(struct Qdisc *sch)
}
}
if (egress_entry) {
if (mini_qdisc_pair_inited(&q->miniqp_egress)) {
egress_entry = rtnl_dereference(dev->tcx_egress);
tcx_miniq_dec(egress_entry);
if (!tcx_entry_is_active(egress_entry)) {
tcx_entry_update(dev, NULL, false);

View File

@@ -146,15 +146,12 @@ teql_destroy(struct Qdisc *sch)
master->slaves = NEXT_SLAVE(q);
if (q == master->slaves) {
struct netdev_queue *txq;
spinlock_t *root_lock;
txq = netdev_get_tx_queue(master->dev, 0);
master->slaves = NULL;
root_lock = qdisc_root_sleeping_lock(rtnl_dereference(txq->qdisc));
spin_lock_bh(root_lock);
qdisc_reset(rtnl_dereference(txq->qdisc));
spin_unlock_bh(root_lock);
dev_reset_queue(master->dev,
txq, NULL);
}
}
skb_queue_purge(&dat->q);

View File

@@ -36,24 +36,6 @@ static struct net_shaper_binding *net_shaper_binding_from_ctx(void *ctx)
return &((struct net_shaper_nl_ctx *)ctx)->binding;
}
static void net_shaper_lock(struct net_shaper_binding *binding)
{
switch (binding->type) {
case NET_SHAPER_BINDING_TYPE_NETDEV:
netdev_lock(binding->netdev);
break;
}
}
static void net_shaper_unlock(struct net_shaper_binding *binding)
{
switch (binding->type) {
case NET_SHAPER_BINDING_TYPE_NETDEV:
netdev_unlock(binding->netdev);
break;
}
}
static struct net_shaper_hierarchy *
net_shaper_hierarchy(struct net_shaper_binding *binding)
{
@@ -65,6 +47,21 @@ net_shaper_hierarchy(struct net_shaper_binding *binding)
return NULL;
}
static struct net_shaper_hierarchy *
net_shaper_hierarchy_rcu(struct net_shaper_binding *binding)
{
/* Readers look up the device and take a ref, then take RCU lock
* later at which point netdev may have been unregistered and flushed.
* READ_ONCE() pairs with WRITE_ONCE() in net_shaper_hierarchy_setup.
*/
if (binding->type == NET_SHAPER_BINDING_TYPE_NETDEV &&
READ_ONCE(binding->netdev->reg_state) <= NETREG_REGISTERED)
return READ_ONCE(binding->netdev->net_shaper_hierarchy);
/* No other type supported yet. */
return NULL;
}
static const struct net_shaper_ops *
net_shaper_ops(struct net_shaper_binding *binding)
{
@@ -204,12 +201,49 @@ static int net_shaper_ctx_setup(const struct genl_info *info, int type,
return 0;
}
/* Like net_shaper_ctx_setup(), but for "write" handlers (never for dumps!)
* Acquires the lock protecting the hierarchy (instance lock for netdev).
*/
static int net_shaper_ctx_setup_lock(const struct genl_info *info, int type,
struct net_shaper_nl_ctx *ctx)
{
struct net *ns = genl_info_net(info);
struct net_device *dev;
int ifindex;
if (GENL_REQ_ATTR_CHECK(info, type))
return -EINVAL;
ifindex = nla_get_u32(info->attrs[type]);
dev = netdev_get_by_index_lock(ns, ifindex);
if (!dev) {
NL_SET_BAD_ATTR(info->extack, info->attrs[type]);
return -ENOENT;
}
if (!dev->netdev_ops->net_shaper_ops) {
NL_SET_BAD_ATTR(info->extack, info->attrs[type]);
netdev_unlock(dev);
return -EOPNOTSUPP;
}
ctx->binding.type = NET_SHAPER_BINDING_TYPE_NETDEV;
ctx->binding.netdev = dev;
return 0;
}
static void net_shaper_ctx_cleanup(struct net_shaper_nl_ctx *ctx)
{
if (ctx->binding.type == NET_SHAPER_BINDING_TYPE_NETDEV)
netdev_put(ctx->binding.netdev, &ctx->dev_tracker);
}
static void net_shaper_ctx_cleanup_unlock(struct net_shaper_nl_ctx *ctx)
{
if (ctx->binding.type == NET_SHAPER_BINDING_TYPE_NETDEV)
netdev_unlock(ctx->binding.netdev);
}
static u32 net_shaper_handle_to_index(const struct net_shaper_handle *handle)
{
return FIELD_PREP(NET_SHAPER_SCOPE_MASK, handle->scope) |
@@ -251,9 +285,10 @@ static struct net_shaper *
net_shaper_lookup(struct net_shaper_binding *binding,
const struct net_shaper_handle *handle)
{
struct net_shaper_hierarchy *hierarchy = net_shaper_hierarchy(binding);
u32 index = net_shaper_handle_to_index(handle);
struct net_shaper_hierarchy *hierarchy;
hierarchy = net_shaper_hierarchy_rcu(binding);
if (!hierarchy || xa_get_mark(&hierarchy->shapers, index,
NET_SHAPER_NOT_VALID))
return NULL;
@@ -262,7 +297,7 @@ net_shaper_lookup(struct net_shaper_binding *binding,
}
/* Allocate on demand the per device shaper's hierarchy container.
* Called under the net shaper lock
* Called under the lock protecting the hierarchy (instance lock for netdev)
*/
static struct net_shaper_hierarchy *
net_shaper_hierarchy_setup(struct net_shaper_binding *binding)
@@ -681,6 +716,22 @@ void net_shaper_nl_post_doit(const struct genl_split_ops *ops,
net_shaper_generic_post(info);
}
int net_shaper_nl_pre_doit_write(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info)
{
struct net_shaper_nl_ctx *ctx = (struct net_shaper_nl_ctx *)info->ctx;
BUILD_BUG_ON(sizeof(*ctx) > sizeof(info->ctx));
return net_shaper_ctx_setup_lock(info, NET_SHAPER_A_IFINDEX, ctx);
}
void net_shaper_nl_post_doit_write(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info)
{
net_shaper_ctx_cleanup_unlock((struct net_shaper_nl_ctx *)info->ctx);
}
int net_shaper_nl_pre_dumpit(struct netlink_callback *cb)
{
struct net_shaper_nl_ctx *ctx = (struct net_shaper_nl_ctx *)cb->ctx;
@@ -778,17 +829,19 @@ int net_shaper_nl_get_dumpit(struct sk_buff *skb,
/* Don't error out dumps performed before any set operation. */
binding = net_shaper_binding_from_ctx(ctx);
hierarchy = net_shaper_hierarchy(binding);
if (!hierarchy)
return 0;
rcu_read_lock();
hierarchy = net_shaper_hierarchy_rcu(binding);
if (!hierarchy)
goto out_unlock;
for (; (shaper = xa_find(&hierarchy->shapers, &ctx->start_index,
U32_MAX, XA_PRESENT)); ctx->start_index++) {
ret = net_shaper_fill_one(skb, binding, shaper, info);
if (ret)
break;
}
out_unlock:
rcu_read_unlock();
return ret;
@@ -806,45 +859,38 @@ int net_shaper_nl_set_doit(struct sk_buff *skb, struct genl_info *info)
binding = net_shaper_binding_from_ctx(info->ctx);
net_shaper_lock(binding);
ret = net_shaper_parse_info(binding, info->attrs, info, &shaper,
&exists);
if (ret)
goto unlock;
return ret;
if (!exists)
net_shaper_default_parent(&shaper.handle, &shaper.parent);
hierarchy = net_shaper_hierarchy_setup(binding);
if (!hierarchy) {
ret = -ENOMEM;
goto unlock;
}
if (!hierarchy)
return -ENOMEM;
/* The 'set' operation can't create node-scope shapers. */
handle = shaper.handle;
if (handle.scope == NET_SHAPER_SCOPE_NODE &&
!net_shaper_lookup(binding, &handle)) {
ret = -ENOENT;
goto unlock;
}
!net_shaper_lookup(binding, &handle))
return -ENOENT;
ret = net_shaper_pre_insert(binding, &handle, info->extack);
if (ret)
goto unlock;
return ret;
ops = net_shaper_ops(binding);
ret = ops->set(binding, &shaper, info->extack);
if (ret) {
net_shaper_rollback(binding);
goto unlock;
return ret;
}
net_shaper_commit(binding, 1, &shaper);
unlock:
net_shaper_unlock(binding);
return ret;
return 0;
}
static int __net_shaper_delete(struct net_shaper_binding *binding,
@@ -1072,35 +1118,26 @@ int net_shaper_nl_delete_doit(struct sk_buff *skb, struct genl_info *info)
binding = net_shaper_binding_from_ctx(info->ctx);
net_shaper_lock(binding);
ret = net_shaper_parse_handle(info->attrs[NET_SHAPER_A_HANDLE], info,
&handle);
if (ret)
goto unlock;
return ret;
hierarchy = net_shaper_hierarchy(binding);
if (!hierarchy) {
ret = -ENOENT;
goto unlock;
}
if (!hierarchy)
return -ENOENT;
shaper = net_shaper_lookup(binding, &handle);
if (!shaper) {
ret = -ENOENT;
goto unlock;
}
if (!shaper)
return -ENOENT;
if (handle.scope == NET_SHAPER_SCOPE_NODE) {
ret = net_shaper_pre_del_node(binding, shaper, info->extack);
if (ret)
goto unlock;
return ret;
}
ret = __net_shaper_delete(binding, shaper, info->extack);
unlock:
net_shaper_unlock(binding);
return ret;
return __net_shaper_delete(binding, shaper, info->extack);
}
static int net_shaper_group_send_reply(struct net_shaper_binding *binding,
@@ -1149,21 +1186,17 @@ int net_shaper_nl_group_doit(struct sk_buff *skb, struct genl_info *info)
if (!net_shaper_ops(binding)->group)
return -EOPNOTSUPP;
net_shaper_lock(binding);
leaves_count = net_shaper_list_len(info, NET_SHAPER_A_LEAVES);
if (!leaves_count) {
NL_SET_BAD_ATTR(info->extack,
info->attrs[NET_SHAPER_A_LEAVES]);
ret = -EINVAL;
goto unlock;
return -EINVAL;
}
leaves = kcalloc(leaves_count, sizeof(struct net_shaper) +
sizeof(struct net_shaper *), GFP_KERNEL);
if (!leaves) {
ret = -ENOMEM;
goto unlock;
}
if (!leaves)
return -ENOMEM;
old_nodes = (void *)&leaves[leaves_count];
ret = net_shaper_parse_node(binding, info->attrs, info, &node);
@@ -1240,9 +1273,6 @@ int net_shaper_nl_group_doit(struct sk_buff *skb, struct genl_info *info)
free_leaves:
kfree(leaves);
unlock:
net_shaper_unlock(binding);
return ret;
free_msg:
@@ -1352,14 +1382,12 @@ static void net_shaper_flush(struct net_shaper_binding *binding)
if (!hierarchy)
return;
net_shaper_lock(binding);
xa_lock(&hierarchy->shapers);
xa_for_each(&hierarchy->shapers, index, cur) {
__xa_erase(&hierarchy->shapers, index);
kfree(cur);
}
xa_unlock(&hierarchy->shapers);
net_shaper_unlock(binding);
kfree(hierarchy);
}

View File

@@ -99,27 +99,27 @@ static const struct genl_split_ops net_shaper_nl_ops[] = {
},
{
.cmd = NET_SHAPER_CMD_SET,
.pre_doit = net_shaper_nl_pre_doit,
.pre_doit = net_shaper_nl_pre_doit_write,
.doit = net_shaper_nl_set_doit,
.post_doit = net_shaper_nl_post_doit,
.post_doit = net_shaper_nl_post_doit_write,
.policy = net_shaper_set_nl_policy,
.maxattr = NET_SHAPER_A_IFINDEX,
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
},
{
.cmd = NET_SHAPER_CMD_DELETE,
.pre_doit = net_shaper_nl_pre_doit,
.pre_doit = net_shaper_nl_pre_doit_write,
.doit = net_shaper_nl_delete_doit,
.post_doit = net_shaper_nl_post_doit,
.post_doit = net_shaper_nl_post_doit_write,
.policy = net_shaper_delete_nl_policy,
.maxattr = NET_SHAPER_A_IFINDEX,
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
},
{
.cmd = NET_SHAPER_CMD_GROUP,
.pre_doit = net_shaper_nl_pre_doit,
.pre_doit = net_shaper_nl_pre_doit_write,
.doit = net_shaper_nl_group_doit,
.post_doit = net_shaper_nl_post_doit,
.post_doit = net_shaper_nl_post_doit_write,
.policy = net_shaper_group_nl_policy,
.maxattr = NET_SHAPER_A_LEAVES,
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,

View File

@@ -18,12 +18,17 @@ extern const struct nla_policy net_shaper_leaf_info_nl_policy[NET_SHAPER_A_WEIGH
int net_shaper_nl_pre_doit(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info);
int net_shaper_nl_pre_doit_write(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info);
int net_shaper_nl_cap_pre_doit(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info);
void
net_shaper_nl_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
struct genl_info *info);
void
net_shaper_nl_post_doit_write(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info);
void
net_shaper_nl_cap_post_doit(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info);
int net_shaper_nl_pre_dumpit(struct netlink_callback *cb);

View File

@@ -131,7 +131,14 @@ static struct sock *smc_tcp_syn_recv_sock(const struct sock *sk,
struct smc_sock *smc;
struct sock *child;
smc = smc_clcsock_user_data(sk);
rcu_read_lock();
smc = smc_clcsock_user_data_rcu(sk);
if (!smc || !refcount_inc_not_zero(&smc->sk.sk_refcnt)) {
rcu_read_unlock();
smc = NULL;
goto drop;
}
rcu_read_unlock();
if (READ_ONCE(sk->sk_ack_backlog) + atomic_read(&smc->queued_smc_hs) >
sk->sk_max_ack_backlog)
@@ -153,11 +160,14 @@ static struct sock *smc_tcp_syn_recv_sock(const struct sock *sk,
if (inet_csk(child)->icsk_af_ops == inet_csk(sk)->icsk_af_ops)
inet_csk(child)->icsk_af_ops = smc->ori_af_ops;
}
sock_put(&smc->sk);
return child;
drop:
dst_release(dst);
tcp_listendrop(sk);
if (smc)
sock_put(&smc->sk);
return NULL;
}
@@ -254,7 +264,7 @@ static void smc_fback_restore_callbacks(struct smc_sock *smc)
struct sock *clcsk = smc->clcsock->sk;
write_lock_bh(&clcsk->sk_callback_lock);
clcsk->sk_user_data = NULL;
rcu_assign_sk_user_data(clcsk, NULL);
smc_clcsock_restore_cb(&clcsk->sk_state_change, &smc->clcsk_state_change);
smc_clcsock_restore_cb(&clcsk->sk_data_ready, &smc->clcsk_data_ready);
@@ -902,7 +912,7 @@ static void smc_fback_replace_callbacks(struct smc_sock *smc)
struct sock *clcsk = smc->clcsock->sk;
write_lock_bh(&clcsk->sk_callback_lock);
clcsk->sk_user_data = (void *)((uintptr_t)smc | SK_USER_DATA_NOCOPY);
__rcu_assign_sk_user_data_with_flags(clcsk, smc, SK_USER_DATA_NOCOPY);
smc_clcsock_replace_cb(&clcsk->sk_state_change, smc_fback_state_change,
&smc->clcsk_state_change);
@@ -2665,8 +2675,8 @@ int smc_listen(struct socket *sock, int backlog)
* smc-specific sk_data_ready function
*/
write_lock_bh(&smc->clcsock->sk->sk_callback_lock);
smc->clcsock->sk->sk_user_data =
(void *)((uintptr_t)smc | SK_USER_DATA_NOCOPY);
__rcu_assign_sk_user_data_with_flags(smc->clcsock->sk, smc,
SK_USER_DATA_NOCOPY);
smc_clcsock_replace_cb(&smc->clcsock->sk->sk_data_ready,
smc_clcsock_data_ready, &smc->clcsk_data_ready);
write_unlock_bh(&smc->clcsock->sk->sk_callback_lock);
@@ -2687,10 +2697,11 @@ int smc_listen(struct socket *sock, int backlog)
write_lock_bh(&smc->clcsock->sk->sk_callback_lock);
smc_clcsock_restore_cb(&smc->clcsock->sk->sk_data_ready,
&smc->clcsk_data_ready);
smc->clcsock->sk->sk_user_data = NULL;
rcu_assign_sk_user_data(smc->clcsock->sk, NULL);
write_unlock_bh(&smc->clcsock->sk->sk_callback_lock);
goto out;
}
sock_set_flag(sk, SOCK_RCU_FREE);
sk->sk_max_ack_backlog = backlog;
sk->sk_ack_backlog = 0;
sk->sk_state = SMC_LISTEN;

View File

@@ -346,6 +346,11 @@ static inline struct smc_sock *smc_clcsock_user_data(const struct sock *clcsk)
((uintptr_t)clcsk->sk_user_data & ~SK_USER_DATA_NOCOPY);
}
static inline struct smc_sock *smc_clcsock_user_data_rcu(const struct sock *clcsk)
{
return (struct smc_sock *)rcu_dereference_sk_user_data(clcsk);
}
/* save target_cb in saved_cb, and replace target_cb with new_cb */
static inline void smc_clcsock_replace_cb(void (**target_cb)(struct sock *),
void (*new_cb)(struct sock *),

View File

@@ -218,7 +218,7 @@ again:
write_lock_bh(&smc->clcsock->sk->sk_callback_lock);
smc_clcsock_restore_cb(&smc->clcsock->sk->sk_data_ready,
&smc->clcsk_data_ready);
smc->clcsock->sk->sk_user_data = NULL;
rcu_assign_sk_user_data(smc->clcsock->sk, NULL);
write_unlock_bh(&smc->clcsock->sk->sk_callback_lock);
rc = kernel_sock_shutdown(smc->clcsock, SHUT_RDWR);
}

View File

@@ -1958,6 +1958,8 @@ static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb)
static void unix_peek_fds(struct scm_cookie *scm, struct sk_buff *skb)
{
scm->fp = scm_fp_dup(UNIXCB(skb).fp);
unix_peek_fpl(scm->fp);
}
static void unix_destruct_scm(struct sk_buff *skb)

View File

@@ -29,6 +29,7 @@ void unix_del_edges(struct scm_fp_list *fpl);
void unix_update_edges(struct unix_sock *receiver);
int unix_prepare_fpl(struct scm_fp_list *fpl);
void unix_destroy_fpl(struct scm_fp_list *fpl);
void unix_peek_fpl(struct scm_fp_list *fpl);
void unix_schedule_gc(struct user_struct *user);
/* SOCK_DIAG */

View File

@@ -318,6 +318,25 @@ void unix_destroy_fpl(struct scm_fp_list *fpl)
unix_free_vertices(fpl);
}
static bool gc_in_progress;
static seqcount_t unix_peek_seq = SEQCNT_ZERO(unix_peek_seq);
void unix_peek_fpl(struct scm_fp_list *fpl)
{
static DEFINE_SPINLOCK(unix_peek_lock);
if (!fpl || !fpl->count_unix)
return;
if (!READ_ONCE(gc_in_progress))
return;
/* Invalidate the final refcnt check in unix_vertex_dead(). */
spin_lock(&unix_peek_lock);
raw_write_seqcount_barrier(&unix_peek_seq);
spin_unlock(&unix_peek_lock);
}
static bool unix_vertex_dead(struct unix_vertex *vertex)
{
struct unix_edge *edge;
@@ -351,6 +370,36 @@ static bool unix_vertex_dead(struct unix_vertex *vertex)
return true;
}
static LIST_HEAD(unix_visited_vertices);
static unsigned long unix_vertex_grouped_index = UNIX_VERTEX_INDEX_MARK2;
static bool unix_scc_dead(struct list_head *scc, bool fast)
{
struct unix_vertex *vertex;
bool scc_dead = true;
unsigned int seq;
seq = read_seqcount_begin(&unix_peek_seq);
list_for_each_entry_reverse(vertex, scc, scc_entry) {
/* Don't restart DFS from this vertex. */
list_move_tail(&vertex->entry, &unix_visited_vertices);
/* Mark vertex as off-stack for __unix_walk_scc(). */
if (!fast)
vertex->index = unix_vertex_grouped_index;
if (scc_dead)
scc_dead = unix_vertex_dead(vertex);
}
/* If MSG_PEEK intervened, defer this SCC to the next round. */
if (read_seqcount_retry(&unix_peek_seq, seq))
return false;
return scc_dead;
}
static void unix_collect_skb(struct list_head *scc, struct sk_buff_head *hitlist)
{
struct unix_vertex *vertex;
@@ -404,9 +453,6 @@ static bool unix_scc_cyclic(struct list_head *scc)
return false;
}
static LIST_HEAD(unix_visited_vertices);
static unsigned long unix_vertex_grouped_index = UNIX_VERTEX_INDEX_MARK2;
static unsigned long __unix_walk_scc(struct unix_vertex *vertex,
unsigned long *last_index,
struct sk_buff_head *hitlist)
@@ -474,9 +520,7 @@ prev_vertex:
}
if (vertex->index == vertex->scc_index) {
struct unix_vertex *v;
struct list_head scc;
bool scc_dead = true;
/* SCC finalised.
*
@@ -485,18 +529,7 @@ prev_vertex:
*/
__list_cut_position(&scc, &vertex_stack, &vertex->scc_entry);
list_for_each_entry_reverse(v, &scc, scc_entry) {
/* Don't restart DFS from this vertex in unix_walk_scc(). */
list_move_tail(&v->entry, &unix_visited_vertices);
/* Mark vertex as off-stack. */
v->index = unix_vertex_grouped_index;
if (scc_dead)
scc_dead = unix_vertex_dead(v);
}
if (scc_dead) {
if (unix_scc_dead(&scc, false)) {
unix_collect_skb(&scc, hitlist);
} else {
if (unix_vertex_max_scc_index < vertex->scc_index)
@@ -550,19 +583,11 @@ static void unix_walk_scc_fast(struct sk_buff_head *hitlist)
while (!list_empty(&unix_unvisited_vertices)) {
struct unix_vertex *vertex;
struct list_head scc;
bool scc_dead = true;
vertex = list_first_entry(&unix_unvisited_vertices, typeof(*vertex), entry);
list_add(&scc, &vertex->scc_entry);
list_for_each_entry_reverse(vertex, &scc, scc_entry) {
list_move_tail(&vertex->entry, &unix_visited_vertices);
if (scc_dead)
scc_dead = unix_vertex_dead(vertex);
}
if (scc_dead) {
if (unix_scc_dead(&scc, true)) {
cyclic_sccs--;
unix_collect_skb(&scc, hitlist);
}
@@ -577,8 +602,6 @@ static void unix_walk_scc_fast(struct sk_buff_head *hitlist)
cyclic_sccs ? UNIX_GRAPH_CYCLIC : UNIX_GRAPH_NOT_CYCLIC);
}
static bool gc_in_progress;
static void unix_gc(struct work_struct *work)
{
struct sk_buff_head hitlist;

View File

@@ -664,6 +664,7 @@ void cfg80211_pmsr_wdev_down(struct wireless_dev *wdev)
}
spin_unlock_bh(&wdev->pmsr_lock);
cancel_work_sync(&wdev->pmsr_free_wk);
if (found)
cfg80211_pmsr_process_abort(wdev);