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] flags: [admin-perm]
do: do:
pre: net-shaper-nl-pre-doit pre: net-shaper-nl-pre-doit-write
post: net-shaper-nl-post-doit post: net-shaper-nl-post-doit-write
request: request:
attributes: attributes:
- ifindex - ifindex
@@ -278,8 +278,8 @@ operations:
flags: [admin-perm] flags: [admin-perm]
do: do:
pre: net-shaper-nl-pre-doit pre: net-shaper-nl-pre-doit-write
post: net-shaper-nl-post-doit post: net-shaper-nl-post-doit-write
request: request:
attributes: *ns-binding attributes: *ns-binding
@@ -309,8 +309,8 @@ operations:
flags: [admin-perm] flags: [admin-perm]
do: do:
pre: net-shaper-nl-pre-doit pre: net-shaper-nl-pre-doit-write
post: net-shaper-nl-post-doit post: net-shaper-nl-post-doit-write
request: request:
attributes: attributes:
- ifindex - ifindex

View File

@@ -787,6 +787,8 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
*/ */
if (soc_type == QCA_WCN3988) if (soc_type == QCA_WCN3988)
rom_ver = ((soc_ver & 0x00000f00) >> 0x05) | (soc_ver & 0x0000000f); 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 else
rom_ver = ((soc_ver & 0x00000f00) >> 0x04) | (soc_ver & 0x0000000f); 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); 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; 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; for (; hash_index != RLB_NULL_INDEX;
hash_index = client_info->used_next) { hash_index = client_info->used_next) {
client_info = &(bond_info->rx_hashtbl[hash_index]); client_info = &(bond_info->rx_hashtbl[hash_index]);
seq_printf(m, "%-15pI4 %-15pI4 %-17pM %s\n", if (client_info->slave)
&client_info->ip_src, seq_printf(m, "%-15pI4 %-15pI4 %-17pM %s\n",
&client_info->ip_dst, &client_info->ip_src,
&client_info->mac_dst, &client_info->ip_dst,
client_info->slave->dev->name); &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); 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; 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; const struct header_ops *slave_ops;
struct slave *slave; struct slave *slave;
int ret = 0; int ret = 0;
@@ -1542,7 +1544,7 @@ static int bond_header_parse(const struct sk_buff *skb, unsigned char *haddr)
if (slave) { if (slave) {
slave_ops = READ_ONCE(slave->dev->header_ops); slave_ops = READ_ONCE(slave->dev->header_ops);
if (slave_ops && slave_ops->parse) if (slave_ops && slave_ops->parse)
ret = slave_ops->parse(skb, haddr); ret = slave_ops->parse(skb, slave->dev, haddr);
} }
rcu_read_unlock(); rcu_read_unlock();
return ret; return ret;

View File

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

View File

@@ -3083,7 +3083,6 @@ static void airoha_remove(struct platform_device *pdev)
if (!port) if (!port)
continue; continue;
airoha_dev_stop(port->dev);
unregister_netdev(port->dev); unregister_netdev(port->dev);
airoha_metadata_dst_free(port); 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); u16 type = (u16)BNXT_EVENT_BUF_PRODUCER_TYPE(data1);
u32 offset = BNXT_EVENT_BUF_PRODUCER_OFFSET(data2); 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); bnxt_bs_trace_check_wrap(&bp->bs_trace[type], offset);
goto async_event_process_exit; 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_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 { struct bnxt_bs_trace_info {
u8 *magic_byte; 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) while (!(bcmgenet_rbuf_readl(priv, RBUF_STATUS)
& RBUF_STATUS_WOL)) { & RBUF_STATUS_WOL)) {
retries++; retries++;
if (retries > 5) { if (retries > 50) {
netdev_crit(dev, "polling wol mode timeout\n"); netdev_crit(dev, "polling wol mode timeout\n");
return -ETIMEDOUT; return -ETIMEDOUT;
} }

View File

@@ -17029,6 +17029,13 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
return err; 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) static int tg3_get_device_address(struct tg3 *tp, u8 *addr)
{ {
u32 hi, lo, mac_offset; 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)) if (!is_valid_ether_addr(addr))
return -EINVAL; return -EINVAL;
if (tg3_is_default_mac_address(addr))
return device_get_mac_address(&tp->pdev->dev, addr);
return 0; return 0;
} }

View File

@@ -2669,6 +2669,14 @@ static void macb_init_tieoff(struct macb *bp)
desc->ctrl = 0; 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) static void gem_init_rings(struct macb *bp)
{ {
struct macb_queue *queue; struct macb_queue *queue;
@@ -2686,10 +2694,7 @@ static void gem_init_rings(struct macb *bp)
queue->tx_head = 0; queue->tx_head = 0;
queue->tx_tail = 0; queue->tx_tail = 0;
queue->rx_tail = 0; gem_init_rx_ring(queue);
queue->rx_prepared_head = 0;
gem_rx_refill(queue);
} }
macb_init_tieoff(bp); 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); struct macb *bp = netdev_priv(netdev);
int ret; int ret;
if (!(netdev->hw_features & NETIF_F_NTUPLE))
return -EOPNOTSUPP;
switch (cmd->cmd) { switch (cmd->cmd) {
case ETHTOOL_SRXCLSRLINS: case ETHTOOL_SRXCLSRLINS:
if ((cmd->fs.location >= bp->max_tuples) if ((cmd->fs.location >= bp->max_tuples)
@@ -5947,8 +5955,18 @@ static int __maybe_unused macb_resume(struct device *dev)
rtnl_unlock(); rtnl_unlock();
} }
if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC))
macb_init_buffers(bp);
for (q = 0, queue = bp->queues; q < bp->num_queues; for (q = 0, queue = bp->queues; q < bp->num_queues;
++q, ++queue) { ++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_rx);
napi_enable(&queue->napi_tx); 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); struct macb *bp = netdev_priv(ndev);
if (bp->ptp_clock) if (bp->ptp_clock) {
ptp_clock_unregister(bp->ptp_clock); ptp_clock_unregister(bp->ptp_clock);
bp->ptp_clock = NULL;
}
gem_ptp_clear_timer(bp); 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++; adapter->num_vlan_filters++;
iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER); iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER);
} else if (f->state == IAVF_VLAN_REMOVE) { } else if (f->state == IAVF_VLAN_REMOVE) {
/* IAVF_VLAN_REMOVE means that VLAN wasn't yet removed. /* Re-add the filter since we cannot tell whether the
* We can safely only change the state here. * 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: clearout:

View File

@@ -781,6 +781,8 @@ int igc_ptp_hwtstamp_set(struct net_device *netdev,
struct kernel_hwtstamp_config *config, struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack); struct netlink_ext_ack *extack);
void igc_ptp_tx_hang(struct igc_adapter *adapter); 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_read(struct igc_adapter *adapter, struct timespec64 *ts);
void igc_ptp_tx_tstamp_event(struct igc_adapter *adapter); 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 */ /* reset next_to_use and next_to_clean */
tx_ring->next_to_use = 0; tx_ring->next_to_use = 0;
tx_ring->next_to_clean = 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 /* The minimum packet size with TCTL.PSP set is 17 so pad the skb
* in order to meet this minimum size requirement. * in order to meet this minimum size requirement.
*/ */
if (skb->len < 17) { if (skb_put_padto(skb, 17))
if (skb_padto(skb, 17)) return NETDEV_TX_OK;
return NETDEV_TX_OK;
skb->len = 17;
}
return igc_xmit_frame_ring(skb, igc_tx_queue_mapping(adapter, skb)); 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); 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) static void igc_ptp_disable_tx_timestamp(struct igc_adapter *adapter)
{ {
struct igc_hw *hw = &adapter->hw; 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); module = libie_find_module_by_dentry(fwlog->debugfs_modules, dentry);
if (module < 0) { if (module < 0) {
dev_info(dev, "unknown module\n"); dev_info(dev, "unknown module\n");
return -EINVAL; count = -EINVAL;
goto free_cmd_buf;
} }
cnt = sscanf(cmd_buf, "%s", user_val); cnt = sscanf(cmd_buf, "%s", user_val);
if (cnt != 1) if (cnt != 1) {
return -EINVAL; count = -EINVAL;
goto free_cmd_buf;
}
log_level = sysfs_match_string(libie_fwlog_level_string, user_val); log_level = sysfs_match_string(libie_fwlog_level_string, user_val);
if (log_level < 0) { if (log_level < 0) {
dev_info(dev, "unknown log level '%s'\n", user_val); 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) { 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; fwlog->cfg.module_entries[i].log_level = log_level;
} }
free_cmd_buf:
kfree(cmd_buf);
return count; return count;
} }
@@ -515,23 +522,31 @@ libie_debugfs_nr_messages_write(struct file *filp, const char __user *buf,
return PTR_ERR(cmd_buf); return PTR_ERR(cmd_buf);
ret = sscanf(cmd_buf, "%s", user_val); ret = sscanf(cmd_buf, "%s", user_val);
if (ret != 1) if (ret != 1) {
return -EINVAL; count = -EINVAL;
goto free_cmd_buf;
}
ret = kstrtos16(user_val, 0, &nr_messages); ret = kstrtos16(user_val, 0, &nr_messages);
if (ret) if (ret) {
return ret; count = ret;
goto free_cmd_buf;
}
if (nr_messages < LIBIE_AQC_FW_LOG_MIN_RESOLUTION || if (nr_messages < LIBIE_AQC_FW_LOG_MIN_RESOLUTION ||
nr_messages > LIBIE_AQC_FW_LOG_MAX_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", 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, nr_messages, LIBIE_AQC_FW_LOG_MIN_RESOLUTION,
LIBIE_AQC_FW_LOG_MAX_RESOLUTION); LIBIE_AQC_FW_LOG_MAX_RESOLUTION);
return -EINVAL; count = -EINVAL;
goto free_cmd_buf;
} }
fwlog->cfg.log_resolution = nr_messages; fwlog->cfg.log_resolution = nr_messages;
free_cmd_buf:
kfree(cmd_buf);
return count; return count;
} }
@@ -588,8 +603,10 @@ libie_debugfs_enable_write(struct file *filp, const char __user *buf,
return PTR_ERR(cmd_buf); return PTR_ERR(cmd_buf);
ret = sscanf(cmd_buf, "%s", user_val); ret = sscanf(cmd_buf, "%s", user_val);
if (ret != 1) if (ret != 1) {
return -EINVAL; ret = -EINVAL;
goto free_cmd_buf;
}
ret = kstrtobool(user_val, &enable); ret = kstrtobool(user_val, &enable);
if (ret) if (ret)
@@ -624,6 +641,8 @@ enable_write_error:
*/ */
if (WARN_ON(ret != (ssize_t)count && ret >= 0)) if (WARN_ON(ret != (ssize_t)count && ret >= 0))
ret = -EIO; ret = -EIO;
free_cmd_buf:
kfree(cmd_buf);
return ret; return ret;
} }
@@ -682,8 +701,10 @@ libie_debugfs_log_size_write(struct file *filp, const char __user *buf,
return PTR_ERR(cmd_buf); return PTR_ERR(cmd_buf);
ret = sscanf(cmd_buf, "%s", user_val); ret = sscanf(cmd_buf, "%s", user_val);
if (ret != 1) if (ret != 1) {
return -EINVAL; ret = -EINVAL;
goto free_cmd_buf;
}
index = sysfs_match_string(libie_fwlog_log_size, user_val); index = sysfs_match_string(libie_fwlog_log_size, user_val);
if (index < 0) { if (index < 0) {
@@ -712,6 +733,8 @@ log_size_write_error:
*/ */
if (WARN_ON(ret != (ssize_t)count && ret >= 0)) if (WARN_ON(ret != (ssize_t)count && ret >= 0))
ret = -EIO; ret = -EIO;
free_cmd_buf:
kfree(cmd_buf);
return ret; return ret;
} }

View File

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

View File

@@ -287,6 +287,7 @@ struct mlx5e_ipsec_sa_entry {
struct mlx5e_ipsec_dwork *dwork; struct mlx5e_ipsec_dwork *dwork;
struct mlx5e_ipsec_limits limits; struct mlx5e_ipsec_limits limits;
u32 rx_mapped_id; u32 rx_mapped_id;
u8 ctx[MLX5_ST_SZ_BYTES(ipsec_aso)];
}; };
struct mlx5_accel_pol_xfrm_attrs { 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); mlx5e_ipsec_aso_query(sa_entry, data);
} }
static void mlx5e_ipsec_update_esn_state(struct mlx5e_ipsec_sa_entry *sa_entry, static void
u32 mode_param) 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 = {}; struct mlx5_wqe_aso_ctrl_seg data = {};
if (mode_param < MLX5E_IPSEC_ESN_SCOPE_MID) { 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; sa_entry->esn_state.overlap = 1;
} }
mlx5e_ipsec_build_accel_xfrm_attrs(sa_entry, &attrs); 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);
data.data_offset_condition_operand = data.data_offset_condition_operand =
MLX5_IPSEC_ASO_REMOVE_FLOW_PKT_CNT_OFFSET; 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) static void mlx5e_ipsec_handle_limits(struct mlx5e_ipsec_sa_entry *sa_entry)
{ {
struct mlx5_accel_esp_xfrm_attrs *attrs = &sa_entry->attrs; 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; bool soft_arm, hard_arm;
u64 hard_cnt; u64 hard_cnt;
lockdep_assert_held(&sa_entry->x->lock); lockdep_assert_held(&sa_entry->x->lock);
soft_arm = !MLX5_GET(ipsec_aso, aso->ctx, soft_lft_arm); soft_arm = !MLX5_GET(ipsec_aso, sa_entry->ctx, soft_lft_arm);
hard_arm = !MLX5_GET(ipsec_aso, aso->ctx, hard_lft_arm); hard_arm = !MLX5_GET(ipsec_aso, sa_entry->ctx, hard_lft_arm);
if (!soft_arm && !hard_arm) if (!soft_arm && !hard_arm)
/* It is not lifetime event */ /* It is not lifetime event */
return; 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) { if (!hard_cnt || hard_arm) {
/* It is possible to see packet counter equal to zero without /* It is possible to see packet counter equal to zero without
* hard limit event armed. Such situation can be if packet * 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 = struct mlx5e_ipsec_work *work =
container_of(_work, struct mlx5e_ipsec_work, work); container_of(_work, struct mlx5e_ipsec_work, work);
struct mlx5e_ipsec_sa_entry *sa_entry = work->data; struct mlx5e_ipsec_sa_entry *sa_entry = work->data;
struct mlx5_accel_esp_xfrm_attrs tmp = {};
struct mlx5_accel_esp_xfrm_attrs *attrs; struct mlx5_accel_esp_xfrm_attrs *attrs;
struct mlx5e_ipsec_aso *aso; bool need_modify = false;
int ret; int ret;
aso = sa_entry->ipsec->aso;
attrs = &sa_entry->attrs; attrs = &sa_entry->attrs;
spin_lock_bh(&sa_entry->x->lock); spin_lock_bh(&sa_entry->x->lock);
@@ -465,18 +453,22 @@ static void mlx5e_ipsec_handle_event(struct work_struct *_work)
if (ret) if (ret)
goto unlock; 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) if (attrs->lft.soft_packet_limit != XFRM_INF)
mlx5e_ipsec_handle_limits(sa_entry); 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: unlock:
spin_unlock_bh(&sa_entry->x->lock); spin_unlock_bh(&sa_entry->x->lock);
if (need_modify)
mlx5_accel_esp_modify_xfrm(sa_entry, &tmp);
kfree(work); kfree(work);
} }
@@ -629,6 +621,8 @@ int mlx5e_ipsec_aso_query(struct mlx5e_ipsec_sa_entry *sa_entry,
/* We are in atomic context */ /* We are in atomic context */
udelay(10); udelay(10);
} while (ret && time_is_after_jiffies(expires)); } 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); spin_unlock_bh(&aso->lock);
return ret; return ret;
} }

View File

@@ -1489,24 +1489,24 @@ out:
return err; 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 ethtool_link_ksettings lksettings;
struct net_device *slave, *master; struct net_device *slave, *master;
u32 speed = SPEED_UNKNOWN; 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); slave = mlx5_uplink_netdev_get(mdev);
if (!slave) if (!slave)
goto out; goto out;
if (take_rtnl)
rtnl_lock();
master = netdev_master_upper_dev_get(slave); master = netdev_master_upper_dev_get(slave);
if (master && !__ethtool_get_link_ksettings(master, &lksettings)) if (master && !__ethtool_get_link_ksettings(master, &lksettings))
speed = lksettings.base.speed; speed = lksettings.base.speed;
if (take_rtnl)
rtnl_unlock();
out: out:
mlx5_uplink_netdev_put(mdev, slave); 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, 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; int err;
if (!mlx5_lag_is_active(mdev)) if (!mlx5_lag_is_active(mdev))
goto skip_lag; goto skip_lag;
if (hold_rtnl_lock) *link_speed_max = mlx5_esw_qos_lag_link_speed_get(mdev, take_rtnl);
rtnl_lock();
*link_speed_max = mlx5_esw_qos_lag_link_speed_get_locked(mdev);
if (hold_rtnl_lock)
rtnl_unlock();
if (*link_speed_max != (u32)SPEED_UNKNOWN) if (*link_speed_max != (u32)SPEED_UNKNOWN)
return 0; return 0;

View File

@@ -814,9 +814,6 @@ void mana_hwc_destroy_channel(struct gdma_context *gc)
gc->max_num_cqs = 0; gc->max_num_cqs = 0;
} }
kfree(hwc->caller_ctx);
hwc->caller_ctx = NULL;
if (hwc->txq) if (hwc->txq)
mana_hwc_destroy_wq(hwc, 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) if (hwc->cq)
mana_hwc_destroy_cq(hwc->gdma_dev->gdma_context, 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); mana_gd_free_res_map(&hwc->inflight_msg_res);
hwc->num_inflight_msg = 0; 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_prepare_buff(&xdp, pa, PRUETH_HEADROOM, pkt_len, false);
*xdp_state = emac_run_xdp(emac, &xdp, &pkt_len); *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) if (*xdp_state != ICSSG_XDP_PASS)
goto requeue; goto requeue;
headroom = xdp.data - xdp.data_hard_start; 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; int ret;
ret = __dev_forward_skb(rx_dev, skb); ret = __dev_forward_skb(rx_dev, skb);
if (ret) if (ret) {
if (psp_ext)
__skb_ext_put(psp_ext);
return ret; return ret;
}
nsim_psp_handle_ext(skb, psp_ext); nsim_psp_handle_ext(skb, psp_ext);

View File

@@ -1395,14 +1395,14 @@ static int aqc111_suspend(struct usb_interface *intf, pm_message_t message)
aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC,
SFR_MEDIUM_STATUS_MODE, 2, &reg16); 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); 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); &aqc111_data->phy_cfg);
} else { } else {
aqc111_data->phy_cfg |= AQ_LOW_POWER; 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); &aqc111_data->phy_cfg);
/* Disable RX path */ /* Disable RX path */
aqc111_read16_cmd_nopm(dev, AQ_ACCESS_MAC, aqc111_read16_cmd_nopm(dev, AQ_ACCESS_MAC,

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 usbnet *dev = netdev_priv(skb_in->dev);
struct usb_cdc_ncm_ndp16 *ndp16; struct usb_cdc_ncm_ndp16 *ndp16;
int ret = -EINVAL; int ret = -EINVAL;
size_t ndp_len;
if ((ndpoffset + sizeof(struct usb_cdc_ncm_ndp16)) > skb_in->len) { if ((ndpoffset + sizeof(struct usb_cdc_ncm_ndp16)) > skb_in->len) {
netif_dbg(dev, rx_err, dev->net, "invalid NDP offset <%u>\n", 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)); sizeof(struct usb_cdc_ncm_dpe16));
ret--; /* we process NDP entries except for the last one */ ret--; /* we process NDP entries except for the last one */
if ((sizeof(struct usb_cdc_ncm_ndp16) + ndp_len = struct_size_t(struct usb_cdc_ncm_ndp16, dpe16, ret);
ret * (sizeof(struct usb_cdc_ncm_dpe16))) > skb_in->len) { if (ndpoffset + ndp_len > skb_in->len) {
netif_dbg(dev, rx_err, dev->net, "Invalid nframes = %d\n", ret); netif_dbg(dev, rx_err, dev->net, "Invalid nframes = %d\n", ret);
ret = -EINVAL; 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 usbnet *dev = netdev_priv(skb_in->dev);
struct usb_cdc_ncm_ndp32 *ndp32; struct usb_cdc_ncm_ndp32 *ndp32;
int ret = -EINVAL; int ret = -EINVAL;
size_t ndp_len;
if ((ndpoffset + sizeof(struct usb_cdc_ncm_ndp32)) > skb_in->len) { if ((ndpoffset + sizeof(struct usb_cdc_ncm_ndp32)) > skb_in->len) {
netif_dbg(dev, rx_err, dev->net, "invalid NDP offset <%u>\n", 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)); sizeof(struct usb_cdc_ncm_dpe32));
ret--; /* we process NDP entries except for the last one */ ret--; /* we process NDP entries except for the last one */
if ((sizeof(struct usb_cdc_ncm_ndp32) + ndp_len = struct_size_t(struct usb_cdc_ncm_ndp32, dpe32, ret);
ret * (sizeof(struct usb_cdc_ncm_dpe32))) > skb_in->len) { if (ndpoffset + ndp_len > skb_in->len) {
netif_dbg(dev, rx_err, dev->net, "Invalid nframes = %d\n", ret); netif_dbg(dev, rx_err, dev->net, "Invalid nframes = %d\n", ret);
ret = -EINVAL; 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); skb_set_queue_mapping(skb, IEEE80211_AC_VO);
if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, NULL)) if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, NULL))
goto error; return;
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO]; txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
if (ath_tx_start(sc->hw, skb, &txctl)) 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->priority = 7;
skb_set_queue_mapping(skb, IEEE80211_AC_VO); skb_set_queue_mapping(skb, IEEE80211_AC_VO);
if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) { if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta))
dev_kfree_skb_any(skb);
return false; return false;
}
break; break;
default: default:
return false; return false;

View File

@@ -63,10 +63,8 @@ mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid)
rcu_read_lock(); rcu_read_lock();
if (!ieee80211_tx_prepare_skb(phy->hw, vif, skb, band, NULL)) { if (!ieee80211_tx_prepare_skb(phy->hw, vif, skb, band, NULL))
ieee80211_free_txskb(phy->hw, skb);
goto out; goto out;
}
info = IEEE80211_SKB_CB(skb); info = IEEE80211_SKB_CB(skb);
if (req->no_cck) 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) && if (skb_headroom(skb) < (total_len - skb->len) &&
pskb_expand_head(skb, (total_len - skb->len), 0, GFP_ATOMIC)) { pskb_expand_head(skb, (total_len - skb->len), 0, GFP_ATOMIC)) {
wl1271_free_tx_id(wl, id); wl1271_free_tx_id(wl, id);
return -EAGAIN; return -ENOMEM;
} }
desc = skb_push(skb, total_len - skb->len); 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, hwsim->tmp_chan->band,
NULL)) { NULL)) {
rcu_read_unlock(); rcu_read_unlock();
kfree_skb(probe);
continue; 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]) { if (info->attrs[HWSIM_ATTR_PMSR_SUPPORT]) {
struct cfg80211_pmsr_capabilities *pmsr_capa; struct cfg80211_pmsr_capabilities *pmsr_capa;
pmsr_capa = kmalloc_obj(*pmsr_capa); pmsr_capa = kzalloc_obj(*pmsr_capa);
if (!pmsr_capa) { if (!pmsr_capa) {
ret = -ENOMEM; ret = -ENOMEM;
goto out_free; 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; 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_cansleep(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_en, (mode != NXP_NCI_MODE_COLD) ? 1 : 0);
usleep_range(10000, 15000); usleep_range(10000, 15000);
if (mode == NXP_NCI_MODE_COLD) 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, int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
const void *daddr, const void *saddr, unsigned len); 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, int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh,
__be16 type); __be16 type);
void eth_header_cache_update(struct hh_cache *hh, const struct net_device *dev, 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); 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); 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, int (*create) (struct sk_buff *skb, struct net_device *dev,
unsigned short type, const void *daddr, unsigned short type, const void *daddr,
const void *saddr, unsigned int len); 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); int (*cache)(const struct neighbour *neigh, struct hh_cache *hh, __be16 type);
void (*cache_update)(struct hh_cache *hh, void (*cache_update)(struct hh_cache *hh,
const struct net_device *dev, const struct net_device *dev,
@@ -2155,6 +2157,7 @@ struct net_device {
unsigned long state; unsigned long state;
unsigned int flags; unsigned int flags;
unsigned short hard_header_len; unsigned short hard_header_len;
enum netdev_stat_type pcpu_stat_type:8;
netdev_features_t features; netdev_features_t features;
struct inet6_dev __rcu *ip6_ptr; struct inet6_dev __rcu *ip6_ptr;
__cacheline_group_end(net_device_read_txrx); __cacheline_group_end(net_device_read_txrx);
@@ -2404,8 +2407,6 @@ struct net_device {
void *ml_priv; void *ml_priv;
enum netdev_ml_priv_type ml_priv_type; enum netdev_ml_priv_type ml_priv_type;
enum netdev_stat_type pcpu_stat_type:8;
#if IS_ENABLED(CONFIG_GARP) #if IS_ENABLED(CONFIG_GARP)
struct garp_port __rcu *garp_port; struct garp_port __rcu *garp_port;
#endif #endif
@@ -3446,7 +3447,7 @@ static inline int dev_parse_header(const struct sk_buff *skb,
if (!dev->header_ops || !dev->header_ops->parse) if (!dev->header_ops || !dev->header_ops->parse)
return 0; 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) static inline __be16 dev_parse_header_protocol(const struct sk_buff *skb)

View File

@@ -665,13 +665,29 @@ static inline int iptunnel_pull_offloads(struct sk_buff *skb)
static inline void iptunnel_xmit_stats(struct net_device *dev, int pkt_len) static inline void iptunnel_xmit_stats(struct net_device *dev, int pkt_len)
{ {
if (pkt_len > 0) { if (pkt_len > 0) {
struct pcpu_sw_netstats *tstats = get_cpu_ptr(dev->tstats); if (dev->pcpu_stat_type == NETDEV_PCPU_STAT_DSTATS) {
struct pcpu_dstats *dstats = get_cpu_ptr(dev->dstats);
u64_stats_update_begin(&tstats->syncp); u64_stats_update_begin(&dstats->syncp);
u64_stats_add(&tstats->tx_bytes, pkt_len); u64_stats_add(&dstats->tx_bytes, pkt_len);
u64_stats_inc(&tstats->tx_packets); u64_stats_inc(&dstats->tx_packets);
u64_stats_update_end(&tstats->syncp); u64_stats_update_end(&dstats->syncp);
put_cpu_ptr(tstats); 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);
u64_stats_add(&tstats->tx_bytes, pkt_len);
u64_stats_inc(&tstats->tx_packets);
u64_stats_update_end(&tstats->syncp);
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; return;
} }

View File

@@ -7407,7 +7407,9 @@ void ieee80211_report_wowlan_wakeup(struct ieee80211_vif *vif,
* @band: the band to transmit on * @band: the band to transmit on
* @sta: optional pointer to get the station to send the frame to * @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 * Note: must be called under RCU lock
*/ */

View File

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

View File

@@ -716,6 +716,34 @@ void qdisc_destroy(struct Qdisc *qdisc);
void qdisc_put(struct Qdisc *qdisc); void qdisc_put(struct Qdisc *qdisc);
void qdisc_put_unlocked(struct Qdisc *qdisc); void qdisc_put_unlocked(struct Qdisc *qdisc);
void qdisc_tree_reduce_backlog(struct Qdisc *qdisc, int n, int len); 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 #ifdef CONFIG_NET_SCHED
int qdisc_offload_dump_helper(struct Qdisc *q, enum tc_setup_type type, int qdisc_offload_dump_helper(struct Qdisc *q, enum tc_setup_type type,
void *type_data); 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, void mini_qdisc_pair_block_init(struct mini_Qdisc_pair *miniqp,
struct tcf_block *block); 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); 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)); 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, static inline int udp_sock_create6(struct net *net, struct udp_port_cfg *cfg,
struct socket **sockp) struct socket **sockp)
{ {
return 0; return -EPFNOSUPPORT;
} }
#endif #endif

View File

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

View File

@@ -91,7 +91,7 @@ struct lec_priv {
*/ */
spinlock_t lec_arp_lock; spinlock_t lec_arp_lock;
struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */ 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 */ struct delayed_work lec_arp_work; /* C10 */
unsigned int maximum_unknown_frame_count; 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) if (aggregated_bytes > max_bytes)
return false; return false;
if (skb_tailroom(forw_packet->skb) < packet_len)
return false;
if (packet_num >= BATADV_MAX_AGGREGATION_PACKETS) if (packet_num >= BATADV_MAX_AGGREGATION_PACKETS)
return false; 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; return false;
done: done:
conn->iso_qos = *qos;
if (hci_cmd_sync_queue(hdev, set_cig_params_sync, if (hci_cmd_sync_queue(hdev, set_cig_params_sync,
UINT_PTR(qos->ucast.cig), NULL) < 0) UINT_PTR(qos->ucast.cig), NULL) < 0)
return false; return false;
@@ -2013,8 +2015,6 @@ struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst,
} }
hci_conn_hold(cis); hci_conn_hold(cis);
cis->iso_qos = *qos;
cis->state = BT_BOUND; cis->state = BT_BOUND;
return cis; return cis;

View File

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

View File

@@ -986,7 +986,8 @@ static void session_free(struct kref *ref)
skb_queue_purge(&session->intr_transmit); skb_queue_purge(&session->intr_transmit);
fput(session->intr_sock->file); fput(session->intr_sock->file);
fput(session->ctrl_sock->file); fput(session->ctrl_sock->file);
l2cap_conn_put(session->conn); if (session->conn)
l2cap_conn_put(session->conn);
kfree(session); kfree(session);
} }
@@ -1164,6 +1165,15 @@ static void hidp_session_remove(struct l2cap_conn *conn,
down_write(&hidp_session_sem); 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); hidp_session_terminate(session);
cancel_work_sync(&session->dev_init); 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 * Instead, this call has the same semantics as if user-space tried to
* delete the session. * delete the session.
*/ */
l2cap_unregister_user(session->conn, &session->user); if (session->conn)
l2cap_unregister_user(session->conn, &session->user);
hidp_session_put(session); hidp_session_put(session);
module_put_and_kthread_exit(0); 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) int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user)
{ {
struct hci_dev *hdev = conn->hcon->hdev;
int ret; int ret;
/* We need to check whether l2cap_conn is registered. If it is not, we /* 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 * must not register the l2cap_user. l2cap_conn_del() unregisters
* l2cap_conn objects, but doesn't provide its own locking. Instead, it * l2cap_conn objects under conn->lock, and we use the same lock here
* relies on the parent hci_conn object to be locked. This itself relies * to protect access to conn->users and conn->hchan.
* on the hci_dev object to be locked. So we must lock the hci device */
* here, too. */
hci_dev_lock(hdev); mutex_lock(&conn->lock);
if (!list_empty(&user->list)) { if (!list_empty(&user->list)) {
ret = -EINVAL; ret = -EINVAL;
@@ -1709,16 +1707,14 @@ int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user)
ret = 0; ret = 0;
out_unlock: out_unlock:
hci_dev_unlock(hdev); mutex_unlock(&conn->lock);
return ret; return ret;
} }
EXPORT_SYMBOL(l2cap_register_user); EXPORT_SYMBOL(l2cap_register_user);
void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user) void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user)
{ {
struct hci_dev *hdev = conn->hcon->hdev; mutex_lock(&conn->lock);
hci_dev_lock(hdev);
if (list_empty(&user->list)) if (list_empty(&user->list))
goto out_unlock; goto out_unlock;
@@ -1727,7 +1723,7 @@ void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user)
user->remove(conn, user); user->remove(conn, user);
out_unlock: out_unlock:
hci_dev_unlock(hdev); mutex_unlock(&conn->lock);
} }
EXPORT_SYMBOL(l2cap_unregister_user); EXPORT_SYMBOL(l2cap_unregister_user);
@@ -4616,7 +4612,8 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn,
switch (type) { switch (type) {
case L2CAP_IT_FEAT_MASK: case L2CAP_IT_FEAT_MASK:
conn->feat_mask = get_unaligned_le32(rsp->data); if (cmd_len >= sizeof(*rsp) + sizeof(u32))
conn->feat_mask = get_unaligned_le32(rsp->data);
if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) { if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
struct l2cap_info_req req; struct l2cap_info_req req;
@@ -4635,7 +4632,8 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn,
break; break;
case L2CAP_IT_FIXED_CHAN: case L2CAP_IT_FIXED_CHAN:
conn->remote_fixed_chan = rsp->data[0]; 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_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
conn->info_ident = 0; conn->info_ident = 0;
@@ -5059,7 +5057,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
u16 mtu, mps; u16 mtu, mps;
__le16 psm; __le16 psm;
u8 result, rsp_len = 0; u8 result, rsp_len = 0;
int i, num_scid; int i, num_scid = 0;
bool defer = false; bool defer = false;
if (!enable_ecred) if (!enable_ecred)
@@ -5072,6 +5070,14 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
goto response; 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); cmd_len -= sizeof(*req);
num_scid = cmd_len / sizeof(u16); num_scid = cmd_len / sizeof(u16);
@@ -5424,7 +5430,7 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn,
u8 *data) u8 *data)
{ {
struct l2cap_chan *chan, *tmp; struct l2cap_chan *chan, *tmp;
struct l2cap_ecred_conn_rsp *rsp = (void *) data; struct l2cap_ecred_reconf_rsp *rsp = (void *)data;
u16 result; u16 result;
if (cmd_len < sizeof(*rsp)) 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); result = __le16_to_cpu(rsp->result);
BT_DBG("result 0x%4.4x", rsp->result); BT_DBG("result 0x%4.4x", result);
if (!result) if (!result)
return 0; return 0;
@@ -6662,8 +6668,10 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
return -ENOBUFS; return -ENOBUFS;
} }
if (chan->imtu < skb->len) { if (skb->len > chan->imtu) {
BT_ERR("Too big LE L2CAP PDU"); BT_ERR("Too big LE L2CAP PDU: len %u > %u", skb->len,
chan->imtu);
l2cap_send_disconn_req(chan, ECONNRESET);
return -ENOBUFS; 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); sdu_len, skb->len, chan->imtu);
if (sdu_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; err = -EMSGSIZE;
goto failed; 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) { if (chan->sdu->len + skb->len > chan->sdu_len) {
BT_ERR("Too much LE L2CAP data received"); BT_ERR("Too much LE L2CAP data received");
l2cap_send_disconn_req(chan, ECONNRESET);
err = -EINVAL; err = -EINVAL;
goto failed; goto failed;
} }

View File

@@ -2195,10 +2195,7 @@ static void set_mesh_complete(struct hci_dev *hdev, void *data, int err)
sk = cmd->sk; sk = cmd->sk;
if (status) { if (status) {
mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER, mgmt_cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
status);
mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev, true,
cmd_status_rsp, &status);
goto done; 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_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, "add monitor %d complete, status %d", 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) && if (!test_bit(SMP_FLAG_DEBUG_KEY, &smp->flags) &&
!crypto_memneq(key, smp->local_pk, 64)) { !crypto_memneq(key, smp->local_pk, 64)) {
bt_dev_err(hdev, "Remote and local public keys are identical"); 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); 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 */ /* Empty and free peer MEP list */
hlist_for_each_entry_safe(peer_mep, n_store, &mep->peer_mep_list, head) { 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); hlist_del_rcu(&peer_mep->head);
kfree_rcu(peer_mep, rcu); 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; return -ENOENT;
} }
cc_peer_disable(peer_mep); disable_delayed_work_sync(&peer_mep->ccm_rx_dwork);
hlist_del_rcu(&peer_mep->head); hlist_del_rcu(&peer_mep->head);
kfree_rcu(peer_mep, rcu); 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); EXPORT_SYMBOL(eth_type_trans);
/** int eth_header_parse(const struct sk_buff *skb, const struct net_device *dev,
* eth_header_parse - extract hardware address from packet unsigned char *haddr)
* @skb: packet to extract header from
* @haddr: destination buffer
*/
int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr)
{ {
const struct ethhdr *eth = eth_hdr(skb); const struct ethhdr *eth = eth_hdr(skb);
memcpy(haddr, eth->h_source, ETH_ALEN); memcpy(haddr, eth->h_source, ETH_ALEN);
return ETH_ALEN; return ETH_ALEN;
} }

View File

@@ -1079,10 +1079,12 @@ out:
static bool icmp_tag_validation(int proto) static bool icmp_tag_validation(int proto)
{ {
const struct net_protocol *ipprot;
bool ok; bool ok;
rcu_read_lock(); 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(); rcu_read_unlock();
return ok; 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)); 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); const struct iphdr *iph = (const struct iphdr *) skb_mac_header(skb);
memcpy(haddr, &iph->saddr, 4); 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); hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);
idev = __in6_dev_get(skb->dev); idev = __in6_dev_get(skb->dev);
if (!idev) {
kfree_skb(skb);
return -1;
}
accept_seg6 = min(READ_ONCE(net->ipv6.devconf_all->seg6_enabled), accept_seg6 = min(READ_ONCE(net->ipv6.devconf_all->seg6_enabled),
READ_ONCE(idev->cnf.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; int require_hmac;
idev = __in6_dev_get(skb->dev); idev = __in6_dev_get(skb->dev);
if (!idev)
return false;
srh = (struct ipv6_sr_hdr *)skb_transport_header(skb); 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); __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); ieee80211_stop_mbssid(sdata);
RCU_INIT_POINTER(link_conf->tx_bss_conf, NULL); 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, ieee80211_link_info_change_notify(sdata, link,
BSS_CHANGED_BEACON_ENABLED); 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) { if (sdata->wdev.links[link_id].cac_started) {
chandef = link_conf->chanreq.oper; chandef = link_conf->chanreq.oper;
wiphy_hrtimer_work_cancel(wiphy, &link->dfs_cac_timer_work); 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(); rcu_read_lock();
list_for_each_entry_rcu(sta, &local->sta_list, list_for_each_entry_rcu(sta, &local->sta_list,
list) { list) {
struct ieee80211_sub_if_data *sdata = sta->sdata; struct ieee80211_sub_if_data *sdata;
enum ieee80211_sta_rx_bandwidth new_sta_bw; enum ieee80211_sta_rx_bandwidth new_sta_bw;
unsigned int link_id; unsigned int link_id;
if (!ieee80211_sdata_running(sta->sdata)) if (!ieee80211_sdata_running(sta->sdata))
continue; 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 = struct ieee80211_link_data *link =
rcu_dereference(sdata->link[link_id]); rcu_dereference(sdata->link[link_id]);
struct ieee80211_bss_conf *link_conf; 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, static ssize_t aql_enable_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
bool aql_disabled = static_key_false(&aql_disable.key);
char buf[3]; char buf[3];
size_t len; 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') if (len > 0 && buf[len - 1] == '\n')
buf[len - 1] = 0; buf[len - 1] = 0;
if (buf[0] == '0' && buf[1] == '\0') { if (buf[0] == '0' && buf[1] == '\0')
if (!aql_disabled) static_branch_enable(&aql_disable);
static_branch_inc(&aql_disable); else if (buf[0] == '1' && buf[1] == '\0')
} else if (buf[0] == '1' && buf[1] == '\0') { static_branch_disable(&aql_disable);
if (aql_disabled) else
static_branch_dec(&aql_disable);
} else {
return -EINVAL; return -EINVAL;
}
return count; return count;
} }

View File

@@ -79,6 +79,9 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
* - MDA enabled * - MDA enabled
* - Power management control on fc * - Power management control on fc
*/ */
if (!ie->mesh_config)
return false;
if (!(ifmsh->mesh_id_len == ie->mesh_id_len && if (!(ifmsh->mesh_id_len == ie->mesh_id_len &&
memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 && memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
(ifmsh->mesh_pp_id == ie->mesh_config->meshconf_psel) && (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 = 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) | if (!(link_sinfo->filled & (BIT_ULL(NL80211_STA_INFO_TX_BYTES64) |
BIT_ULL(NL80211_STA_INFO_TX_BYTES)))) { 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->connected_time = ktime_get_seconds() - sta->last_connected;
sinfo->assoc_at = sta->assoc_at; sinfo->assoc_at = sta->assoc_at;
sinfo->inactive_time = 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) | if (!(sinfo->filled & (BIT_ULL(NL80211_STA_INFO_TX_BYTES64) |
BIT_ULL(NL80211_STA_INFO_TX_BYTES)))) { 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); sta = sta_info_get(sdata, peer);
if (!sta) if (!sta || !sta->sta.tdls)
return -ENOLINK; return -ENOLINK;
iee80211_tdls_recalc_chanctx(sdata, sta); 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 ieee80211_tx_data tx;
struct sk_buff *skb2; 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; return false;
}
info->band = band; info->band = band;
info->control.vif = vif; info->control.vif = vif;

View File

@@ -469,7 +469,9 @@ static int mac802154_header_create(struct sk_buff *skb,
} }
static int 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; struct ieee802154_hdr hdr;

View File

@@ -2854,6 +2854,7 @@ out_unregister_rtnl_af:
rtnl_af_unregister(&mpls_af_ops); rtnl_af_unregister(&mpls_af_ops);
out_unregister_dev_type: out_unregister_dev_type:
dev_remove_pack(&mpls_packet_type); dev_remove_pack(&mpls_packet_type);
unregister_netdevice_notifier(&mpls_dev_notifier);
out_unregister_pernet: out_unregister_pernet:
unregister_pernet_subsys(&mpls_net_ops); unregister_pernet_subsys(&mpls_net_ops);
goto out; 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, static int mptcp_pm_nl_create_listen_socket(struct sock *sk,
struct mptcp_pm_addr_entry *entry) 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); int addrlen = sizeof(struct sockaddr_in);
struct sockaddr_storage addr; struct sockaddr_storage addr;
struct sock *newsk, *ssk; 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 = { static const struct bpf_link_ops bpf_nf_link_lops = {
.release = bpf_nf_link_release, .release = bpf_nf_link_release,
.dealloc = bpf_nf_link_dealloc, .dealloc_deferred = bpf_nf_link_dealloc,
.detach = bpf_nf_link_detach, .detach = bpf_nf_link_detach,
.show_fdinfo = bpf_nf_link_show_info, .show_fdinfo = bpf_nf_link_show_info,
.fill_link_info = bpf_nf_link_fill_link_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)) if (nf_h323_error_boundary(bs, 0, 2))
return H323_ERROR_BOUND; return H323_ERROR_BOUND;
len = get_bits(bs, 2) + 1; len = get_bits(bs, 2) + 1;
if (nf_h323_error_boundary(bs, len, 0))
return H323_ERROR_BOUND;
BYTE_ALIGN(bs); BYTE_ALIGN(bs);
if (base && (f->attr & DECODE)) { /* timeToLive */ if (base && (f->attr & DECODE)) { /* timeToLive */
unsigned int v = get_uint(bs, len) + f->lb; unsigned int v = get_uint(bs, len) + f->lb;
@@ -922,6 +924,8 @@ int DecodeQ931(unsigned char *buf, size_t sz, Q931 *q931)
break; break;
p++; p++;
len--; len--;
if (len <= 0)
break;
return DecodeH323_UserInformation(buf, p, len, return DecodeH323_UserInformation(buf, p, len,
&q931->UUIE); &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 nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
struct nf_conn *ct = cb->data; 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; u_int8_t l3proto = nfmsg->nfgen_family;
unsigned long last_id = cb->args[1]; unsigned long last_id = cb->args[1];
struct nf_conntrack_expect *exp; 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]) if (cb->args[0])
return 0; return 0;
help = nfct_help(ct);
if (!help)
return 0;
rcu_read_lock(); rcu_read_lock();
restart: restart:
@@ -3249,6 +3253,24 @@ out:
return skb->len; 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, static int ctnetlink_dump_exp_ct(struct net *net, struct sock *ctnl,
struct sk_buff *skb, struct sk_buff *skb,
const struct nlmsghdr *nlh, 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 nf_conntrack_zone zone;
struct netlink_dump_control c = { struct netlink_dump_control c = {
.dump = ctnetlink_exp_ct_dump_table, .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, 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) #if IS_ENABLED(CONFIG_NF_NAT)
static const struct nla_policy exp_nat_nla_policy[CTA_EXPECT_NAT_MAX+1] = { 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 }, [CTA_EXPECT_NAT_TUPLE] = { .type = NLA_NESTED },
}; };
#endif #endif

View File

@@ -582,7 +582,8 @@ nla_put_failure:
} }
static const struct nla_policy sctp_nla_policy[CTA_PROTOINFO_SCTP_MAX+1] = { 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_ORIGINAL] = { .type = NLA_U32 },
[CTA_PROTOINFO_SCTP_VTAG_REPLY] = { .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; struct tcphdr *th, _tcph;
unsigned int dataoff, datalen; unsigned int dataoff, datalen;
unsigned int matchoff, matchlen, clen; unsigned int matchoff, matchlen;
unsigned int msglen, origlen; unsigned int msglen, origlen;
const char *dptr, *end; const char *dptr, *end;
s16 diff, tdiff = 0; s16 diff, tdiff = 0;
int ret = NF_ACCEPT; int ret = NF_ACCEPT;
unsigned long clen;
bool term; bool term;
if (ctinfo != IP_CT_ESTABLISHED && 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) if (dptr + matchoff == end)
break; break;
if (clen > datalen)
break;
term = false; term = false;
for (; end + strlen("\r\n\r\n") <= dptr + datalen; end++) { for (; end + strlen("\r\n\r\n") <= dptr + datalen; end++) {
if (end[0] == '\r' && end[1] == '\n' && 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) { switch (tuple->encap[i].proto) {
case htons(ETH_P_8021Q): case htons(ETH_P_8021Q):
case htons(ETH_P_8021AD): case htons(ETH_P_8021AD):
skb_reset_mac_header(skb);
if (skb_vlan_push(skb, tuple->encap[i].proto, if (skb_vlan_push(skb, tuple->encap[i].proto,
tuple->encap[i].id) < 0) tuple->encap[i].id) < 0)
return -1; return -1;

View File

@@ -6744,8 +6744,8 @@ 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_set_elem_expr *elem_expr)
{ {
struct nft_expr *expr; struct nft_expr *expr;
u32 size; u32 size;
@@ -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, static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
const struct nlattr *attr, u32 nlmsg_flags, const struct nlattr *attr, u32 nlmsg_flags)
bool last)
{ {
struct nft_expr *expr_array[NFT_SET_EXPR_MAX] = {}; struct nft_expr *expr_array[NFT_SET_EXPR_MAX] = {};
struct nlattr *nla[NFTA_SET_ELEM_MAX + 1]; 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) if (flags)
*nft_set_ext_flags(ext) = flags; *nft_set_ext_flags(ext) = flags;
if (last)
elem.flags = NFT_SET_ELEM_INTERNAL_LAST;
else
elem.flags = 0;
if (obj) if (obj)
*nft_set_ext_obj(ext) = 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); nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) { nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
err = nft_add_set_elem(&ctx, set, attr, info->nlh->nlmsg_flags, err = nft_add_set_elem(&ctx, set, attr, info->nlh->nlmsg_flags);
nla_is_last(attr, rem));
if (err < 0) { if (err < 0) {
NL_SET_BAD_ATTR(extack, attr); NL_SET_BAD_ATTR(extack, attr);
return err; 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, 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 nlattr *nla[NFTA_SET_ELEM_MAX + 1];
struct nft_set_ext_tmpl tmpl; 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) if (flags)
*nft_set_ext_flags(ext) = 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); trans = nft_trans_elem_alloc(ctx, NFT_MSG_DELSETELEM, set);
if (trans == NULL) if (trans == NULL)
goto fail_trans; goto fail_trans;
@@ -7961,8 +7949,7 @@ static int nf_tables_delsetelem(struct sk_buff *skb,
return nft_set_flush(&ctx, set, genmask); return nft_set_flush(&ctx, set, genmask);
nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) { nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
err = nft_del_setelem(&ctx, set, attr, err = nft_del_setelem(&ctx, set, attr);
nla_is_last(attr, rem));
if (err == -ENOENT && if (err == -ENOENT &&
NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYSETELEM) NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYSETELEM)
continue; continue;
@@ -9216,6 +9203,7 @@ static int nf_tables_newflowtable(struct sk_buff *skb,
return 0; return 0;
err_flowtable_hooks: err_flowtable_hooks:
synchronize_rcu();
nft_trans_destroy(trans); nft_trans_destroy(trans);
err_flowtable_trans: err_flowtable_trans:
nft_hooks_destroy(&flowtable->hook_list); 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_user_finger *f;
struct nf_osf_finger *kf = NULL, *sf; struct nf_osf_finger *kf = NULL, *sf;
unsigned int tot_opt_len = 0;
int err = 0; int err = 0;
int i;
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
@@ -318,6 +320,17 @@ static int nfnl_osf_add_callback(struct sk_buff *skb,
if (f->opt_num > ARRAY_SIZE(f->opt)) if (f->opt_num > ARRAY_SIZE(f->opt))
return -EINVAL; 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) || if (!memchr(f->genre, 0, MAXGENRELEN) ||
!memchr(f->subtype, 0, MAXGENRELEN) || !memchr(f->subtype, 0, MAXGENRELEN) ||
!memchr(f->version, 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_l4proto.h>
#include <net/netfilter/nf_conntrack_expect.h> #include <net/netfilter/nf_conntrack_expect.h>
#include <net/netfilter/nf_conntrack_seqadj.h> #include <net/netfilter/nf_conntrack_seqadj.h>
#include "nf_internals.h"
struct nft_ct_helper_obj { struct nft_ct_helper_obj {
struct nf_conntrack_helper *helper4; 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 #endif
#ifdef CONFIG_NF_CONNTRACK_ZONES #ifdef CONFIG_NF_CONNTRACK_ZONES
case NFT_CT_ZONE: case NFT_CT_ZONE:
nf_queue_nf_hook_drop(ctx->net);
mutex_lock(&nft_ct_pcpu_mutex); mutex_lock(&nft_ct_pcpu_mutex);
if (--nft_ct_pcpu_template_refcnt == 0) if (--nft_ct_pcpu_template_refcnt == 0)
nft_ct_tmpl_put_pcpu(); 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 nft_ct_timeout_obj *priv = nft_obj_data(obj);
struct nf_ct_timeout *timeout = priv->timeout; struct nf_ct_timeout *timeout = priv->timeout;
nf_queue_nf_hook_drop(ctx->net);
nf_ct_untimeout(ctx->net, timeout); nf_ct_untimeout(ctx->net, timeout);
nf_ct_netns_put(ctx->net, ctx->family); nf_ct_netns_put(ctx->net, ctx->family);
kfree(priv->timeout); 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); struct nft_ct_helper_obj *priv = nft_obj_data(obj);
nf_queue_nf_hook_drop(ctx->net);
if (priv->helper4) if (priv->helper4)
nf_conntrack_helper_put(priv->helper4); nf_conntrack_helper_put(priv->helper4);
if (priv->helper6) 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) const struct nft_set_ext *ext)
{ {
struct nft_set_elem_expr *elem_expr = nft_set_ext_expr(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; struct nft_expr *expr;
int i; int i;
for (i = 0; i < priv->num_exprs; i++) { for (i = 0; i < priv->num_exprs; i++) {
expr = nft_setelem_expr_at(elem_expr, elem_expr->size); expr = nft_setelem_expr_at(elem_expr, elem_expr->size);
if (nft_expr_clone(expr, priv->expr_array[i], GFP_ATOMIC) < 0) 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; elem_expr->size += priv->expr_array[i]->ops->size;
} }
return 0; 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, 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; 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, static bool nft_rbtree_cmp_start_cookie(struct nft_rbtree *priv,
const struct nft_rbtree_elem *rbe) 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, 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, static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
struct nft_rbtree_elem *new, 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 nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL, *rbe_prev;
struct rb_node *node, *next, *parent, **p, *first = NULL; struct rb_node *node, *next, *parent, **p, *first = NULL;
struct nft_rbtree *priv = nft_set_priv(set); struct nft_rbtree *priv = nft_set_priv(set);
u8 cur_genmask = nft_genmask_cur(net); u8 cur_genmask = nft_genmask_cur(net);
u8 genmask = nft_genmask_next(net); u8 genmask = nft_genmask_next(net);
unsigned long open_interval = 0;
int d; int d;
/* Descend the tree to search for an existing element greater than the /* 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)
priv->start_rbe_cookie = 0; priv->start_rbe_cookie = 0;
} else if (nft_rbtree_interval_start(new) && priv->start_rbe_cookie) {
if (nft_set_is_anonymous(set)) {
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 /* - new start element matching existing start element: full overlap
* reported as -EEXIST, cleared by caller if NLM_F_EXCL is not given. * 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) && if (rbe_ge && !nft_rbtree_cmp(set, new, rbe_ge) &&
nft_rbtree_interval_start(rbe_ge) == nft_rbtree_interval_start(new)) { nft_rbtree_interval_start(rbe_ge) == nft_rbtree_interval_start(new)) {
*elem_priv = &rbe_ge->priv; *elem_priv = &rbe_ge->priv;
nft_rbtree_set_start_cookie(priv, rbe_ge);
/* - 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);
return -EEXIST; 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)) nft_rbtree_interval_end(rbe_ge) && nft_rbtree_interval_end(new))
return -ENOTEMPTY; 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 */ /* Accepted element: pick insertion point depending on key value */
parent = NULL; parent = NULL;
p = &priv->root.rb_node; 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_elem_priv **elem_priv)
{ {
struct nft_rbtree_elem *rbe = nft_elem_priv_cast(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); struct nft_rbtree *priv = nft_set_priv(set);
u64 tstamp = nft_net_tstamp(net); u64 tstamp = nft_net_tstamp(net);
int err; int err;
@@ -685,12 +640,8 @@ static int nft_rbtree_insert(const struct net *net, const struct nft_set *set,
cond_resched(); cond_resched();
write_lock_bh(&priv->lock); 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); write_unlock_bh(&priv->lock);
if (nft_rbtree_interval_end(rbe))
priv->start_rbe_cookie = 0;
} while (err == -EAGAIN); } while (err == -EAGAIN);
return err; return err;
@@ -778,7 +729,6 @@ nft_rbtree_deactivate(const struct net *net, const struct nft_set *set,
const struct nft_set_elem *elem) const struct nft_set_elem *elem)
{ {
struct nft_rbtree_elem *rbe, *this = nft_elem_priv_cast(elem->priv); 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); struct nft_rbtree *priv = nft_set_priv(set);
const struct rb_node *parent = priv->root.rb_node; const struct rb_node *parent = priv->root.rb_node;
u8 genmask = nft_genmask_next(net); u8 genmask = nft_genmask_next(net);
@@ -819,10 +769,9 @@ nft_rbtree_deactivate(const struct net *net, const struct nft_set *set,
continue; continue;
} }
if (nft_rbtree_interval_start(rbe)) { if (nft_rbtree_interval_start(rbe))
if (!last) nft_rbtree_set_start_cookie(priv, 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; return NULL;
nft_rbtree_flush(net, set, &rbe->priv); 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_ecache.h>
#include <net/netfilter/nf_conntrack_timeout.h> #include <net/netfilter/nf_conntrack_timeout.h>
#include <net/netfilter/nf_conntrack_zones.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) 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; struct nf_conn_help *help;
if (ct) { if (ct) {
if (info->helper[0] || info->timeout[0])
nf_queue_nf_hook_drop(par->net);
help = nfct_help(ct); help = nfct_help(ct);
xt_ct_put_helper(help); 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); localtime_2(&current_time, stamp);
if (!(info->weekdays_match & (1 << current_time.weekday))) if (!(info->weekdays_match & (1U << current_time.weekday)))
return false; return false;
/* Do not spend time computing monthday if all days match anyway */ /* Do not spend time computing monthday if all days match anyway */
if (info->monthdays_match != XT_TIME_ALL_MONTHDAYS) { if (info->monthdays_match != XT_TIME_ALL_MONTHDAYS) {
localtime_3(&current_time, stamp); localtime_3(&current_time, stamp);
if (!(info->monthdays_match & (1 << current_time.monthday))) if (!(info->monthdays_match & (1U << current_time.monthday)))
return false; return false;
} }

View File

@@ -129,9 +129,12 @@ static int pn_header_create(struct sk_buff *skb, struct net_device *dev,
return 1; 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); const u8 *media = skb_mac_header(skb);
*haddr = *media; *haddr = *media;
return 1; return 1;
} }

View File

@@ -811,6 +811,11 @@ static int rose_connect(struct socket *sock, struct sockaddr_unsized *uaddr, int
goto out_release; goto out_release;
} }
if (sk->sk_state == TCP_SYN_SENT) {
err = -EALREADY;
goto out_release;
}
sk->sk_state = TCP_CLOSE; sk->sk_state = TCP_CLOSE;
sock->state = SS_UNCONNECTED; 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) static bool some_qdisc_is_busy(struct net_device *dev)
{ {
unsigned int i; 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 ingress_sched_data *q = qdisc_priv(sch);
struct net_device *dev = qdisc_dev(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) if (sch->parent != TC_H_INGRESS)
return; return;
tcf_block_put_ext(q->block, sch, &q->block_info); 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); tcx_miniq_dec(entry);
if (!tcx_entry_is_active(entry)) { if (!tcx_entry_is_active(entry)) {
tcx_entry_update(dev, NULL, true); 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) static void clsact_destroy(struct Qdisc *sch)
{ {
struct bpf_mprog_entry *ingress_entry, *egress_entry;
struct clsact_sched_data *q = qdisc_priv(sch); struct clsact_sched_data *q = qdisc_priv(sch);
struct net_device *dev = qdisc_dev(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) if (sch->parent != TC_H_CLSACT)
return; 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->ingress_block, sch, &q->ingress_block_info);
tcf_block_put_ext(q->egress_block, sch, &q->egress_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); tcx_miniq_dec(ingress_entry);
if (!tcx_entry_is_active(ingress_entry)) { if (!tcx_entry_is_active(ingress_entry)) {
tcx_entry_update(dev, NULL, true); 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); tcx_miniq_dec(egress_entry);
if (!tcx_entry_is_active(egress_entry)) { if (!tcx_entry_is_active(egress_entry)) {
tcx_entry_update(dev, NULL, false); tcx_entry_update(dev, NULL, false);

View File

@@ -146,15 +146,12 @@ teql_destroy(struct Qdisc *sch)
master->slaves = NEXT_SLAVE(q); master->slaves = NEXT_SLAVE(q);
if (q == master->slaves) { if (q == master->slaves) {
struct netdev_queue *txq; struct netdev_queue *txq;
spinlock_t *root_lock;
txq = netdev_get_tx_queue(master->dev, 0); txq = netdev_get_tx_queue(master->dev, 0);
master->slaves = NULL; master->slaves = NULL;
root_lock = qdisc_root_sleeping_lock(rtnl_dereference(txq->qdisc)); dev_reset_queue(master->dev,
spin_lock_bh(root_lock); txq, NULL);
qdisc_reset(rtnl_dereference(txq->qdisc));
spin_unlock_bh(root_lock);
} }
} }
skb_queue_purge(&dat->q); 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; 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 * static struct net_shaper_hierarchy *
net_shaper_hierarchy(struct net_shaper_binding *binding) net_shaper_hierarchy(struct net_shaper_binding *binding)
{ {
@@ -65,6 +47,21 @@ net_shaper_hierarchy(struct net_shaper_binding *binding)
return NULL; 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 * static const struct net_shaper_ops *
net_shaper_ops(struct net_shaper_binding *binding) 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; 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) static void net_shaper_ctx_cleanup(struct net_shaper_nl_ctx *ctx)
{ {
if (ctx->binding.type == NET_SHAPER_BINDING_TYPE_NETDEV) if (ctx->binding.type == NET_SHAPER_BINDING_TYPE_NETDEV)
netdev_put(ctx->binding.netdev, &ctx->dev_tracker); 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) static u32 net_shaper_handle_to_index(const struct net_shaper_handle *handle)
{ {
return FIELD_PREP(NET_SHAPER_SCOPE_MASK, handle->scope) | 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, net_shaper_lookup(struct net_shaper_binding *binding,
const struct net_shaper_handle *handle) const struct net_shaper_handle *handle)
{ {
struct net_shaper_hierarchy *hierarchy = net_shaper_hierarchy(binding);
u32 index = net_shaper_handle_to_index(handle); 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, if (!hierarchy || xa_get_mark(&hierarchy->shapers, index,
NET_SHAPER_NOT_VALID)) NET_SHAPER_NOT_VALID))
return NULL; return NULL;
@@ -262,7 +297,7 @@ net_shaper_lookup(struct net_shaper_binding *binding,
} }
/* Allocate on demand the per device shaper's hierarchy container. /* 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 * static struct net_shaper_hierarchy *
net_shaper_hierarchy_setup(struct net_shaper_binding *binding) 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); 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) int net_shaper_nl_pre_dumpit(struct netlink_callback *cb)
{ {
struct net_shaper_nl_ctx *ctx = (struct net_shaper_nl_ctx *)cb->ctx; 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. */ /* Don't error out dumps performed before any set operation. */
binding = net_shaper_binding_from_ctx(ctx); binding = net_shaper_binding_from_ctx(ctx);
hierarchy = net_shaper_hierarchy(binding);
if (!hierarchy)
return 0;
rcu_read_lock(); rcu_read_lock();
hierarchy = net_shaper_hierarchy_rcu(binding);
if (!hierarchy)
goto out_unlock;
for (; (shaper = xa_find(&hierarchy->shapers, &ctx->start_index, for (; (shaper = xa_find(&hierarchy->shapers, &ctx->start_index,
U32_MAX, XA_PRESENT)); ctx->start_index++) { U32_MAX, XA_PRESENT)); ctx->start_index++) {
ret = net_shaper_fill_one(skb, binding, shaper, info); ret = net_shaper_fill_one(skb, binding, shaper, info);
if (ret) if (ret)
break; break;
} }
out_unlock:
rcu_read_unlock(); rcu_read_unlock();
return ret; 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); binding = net_shaper_binding_from_ctx(info->ctx);
net_shaper_lock(binding);
ret = net_shaper_parse_info(binding, info->attrs, info, &shaper, ret = net_shaper_parse_info(binding, info->attrs, info, &shaper,
&exists); &exists);
if (ret) if (ret)
goto unlock; return ret;
if (!exists) if (!exists)
net_shaper_default_parent(&shaper.handle, &shaper.parent); net_shaper_default_parent(&shaper.handle, &shaper.parent);
hierarchy = net_shaper_hierarchy_setup(binding); hierarchy = net_shaper_hierarchy_setup(binding);
if (!hierarchy) { if (!hierarchy)
ret = -ENOMEM; return -ENOMEM;
goto unlock;
}
/* The 'set' operation can't create node-scope shapers. */ /* The 'set' operation can't create node-scope shapers. */
handle = shaper.handle; handle = shaper.handle;
if (handle.scope == NET_SHAPER_SCOPE_NODE && if (handle.scope == NET_SHAPER_SCOPE_NODE &&
!net_shaper_lookup(binding, &handle)) { !net_shaper_lookup(binding, &handle))
ret = -ENOENT; return -ENOENT;
goto unlock;
}
ret = net_shaper_pre_insert(binding, &handle, info->extack); ret = net_shaper_pre_insert(binding, &handle, info->extack);
if (ret) if (ret)
goto unlock; return ret;
ops = net_shaper_ops(binding); ops = net_shaper_ops(binding);
ret = ops->set(binding, &shaper, info->extack); ret = ops->set(binding, &shaper, info->extack);
if (ret) { if (ret) {
net_shaper_rollback(binding); net_shaper_rollback(binding);
goto unlock; return ret;
} }
net_shaper_commit(binding, 1, &shaper); net_shaper_commit(binding, 1, &shaper);
unlock: return 0;
net_shaper_unlock(binding);
return ret;
} }
static int __net_shaper_delete(struct net_shaper_binding *binding, 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); binding = net_shaper_binding_from_ctx(info->ctx);
net_shaper_lock(binding);
ret = net_shaper_parse_handle(info->attrs[NET_SHAPER_A_HANDLE], info, ret = net_shaper_parse_handle(info->attrs[NET_SHAPER_A_HANDLE], info,
&handle); &handle);
if (ret) if (ret)
goto unlock; return ret;
hierarchy = net_shaper_hierarchy(binding); hierarchy = net_shaper_hierarchy(binding);
if (!hierarchy) { if (!hierarchy)
ret = -ENOENT; return -ENOENT;
goto unlock;
}
shaper = net_shaper_lookup(binding, &handle); shaper = net_shaper_lookup(binding, &handle);
if (!shaper) { if (!shaper)
ret = -ENOENT; return -ENOENT;
goto unlock;
}
if (handle.scope == NET_SHAPER_SCOPE_NODE) { if (handle.scope == NET_SHAPER_SCOPE_NODE) {
ret = net_shaper_pre_del_node(binding, shaper, info->extack); ret = net_shaper_pre_del_node(binding, shaper, info->extack);
if (ret) if (ret)
goto unlock; return ret;
} }
ret = __net_shaper_delete(binding, shaper, info->extack); return __net_shaper_delete(binding, shaper, info->extack);
unlock:
net_shaper_unlock(binding);
return ret;
} }
static int net_shaper_group_send_reply(struct net_shaper_binding *binding, 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) if (!net_shaper_ops(binding)->group)
return -EOPNOTSUPP; return -EOPNOTSUPP;
net_shaper_lock(binding);
leaves_count = net_shaper_list_len(info, NET_SHAPER_A_LEAVES); leaves_count = net_shaper_list_len(info, NET_SHAPER_A_LEAVES);
if (!leaves_count) { if (!leaves_count) {
NL_SET_BAD_ATTR(info->extack, NL_SET_BAD_ATTR(info->extack,
info->attrs[NET_SHAPER_A_LEAVES]); info->attrs[NET_SHAPER_A_LEAVES]);
ret = -EINVAL; return -EINVAL;
goto unlock;
} }
leaves = kcalloc(leaves_count, sizeof(struct net_shaper) + leaves = kcalloc(leaves_count, sizeof(struct net_shaper) +
sizeof(struct net_shaper *), GFP_KERNEL); sizeof(struct net_shaper *), GFP_KERNEL);
if (!leaves) { if (!leaves)
ret = -ENOMEM; return -ENOMEM;
goto unlock;
}
old_nodes = (void *)&leaves[leaves_count]; old_nodes = (void *)&leaves[leaves_count];
ret = net_shaper_parse_node(binding, info->attrs, info, &node); 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: free_leaves:
kfree(leaves); kfree(leaves);
unlock:
net_shaper_unlock(binding);
return ret; return ret;
free_msg: free_msg:
@@ -1352,14 +1382,12 @@ static void net_shaper_flush(struct net_shaper_binding *binding)
if (!hierarchy) if (!hierarchy)
return; return;
net_shaper_lock(binding);
xa_lock(&hierarchy->shapers); xa_lock(&hierarchy->shapers);
xa_for_each(&hierarchy->shapers, index, cur) { xa_for_each(&hierarchy->shapers, index, cur) {
__xa_erase(&hierarchy->shapers, index); __xa_erase(&hierarchy->shapers, index);
kfree(cur); kfree(cur);
} }
xa_unlock(&hierarchy->shapers); xa_unlock(&hierarchy->shapers);
net_shaper_unlock(binding);
kfree(hierarchy); kfree(hierarchy);
} }

View File

@@ -99,27 +99,27 @@ static const struct genl_split_ops net_shaper_nl_ops[] = {
}, },
{ {
.cmd = NET_SHAPER_CMD_SET, .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, .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, .policy = net_shaper_set_nl_policy,
.maxattr = NET_SHAPER_A_IFINDEX, .maxattr = NET_SHAPER_A_IFINDEX,
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
}, },
{ {
.cmd = NET_SHAPER_CMD_DELETE, .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, .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, .policy = net_shaper_delete_nl_policy,
.maxattr = NET_SHAPER_A_IFINDEX, .maxattr = NET_SHAPER_A_IFINDEX,
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
}, },
{ {
.cmd = NET_SHAPER_CMD_GROUP, .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, .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, .policy = net_shaper_group_nl_policy,
.maxattr = NET_SHAPER_A_LEAVES, .maxattr = NET_SHAPER_A_LEAVES,
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, .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, int net_shaper_nl_pre_doit(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info); 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, int net_shaper_nl_cap_pre_doit(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info); struct sk_buff *skb, struct genl_info *info);
void void
net_shaper_nl_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, net_shaper_nl_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
struct genl_info *info); struct genl_info *info);
void 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, net_shaper_nl_cap_post_doit(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info); struct sk_buff *skb, struct genl_info *info);
int net_shaper_nl_pre_dumpit(struct netlink_callback *cb); 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 smc_sock *smc;
struct sock *child; 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) > if (READ_ONCE(sk->sk_ack_backlog) + atomic_read(&smc->queued_smc_hs) >
sk->sk_max_ack_backlog) 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) if (inet_csk(child)->icsk_af_ops == inet_csk(sk)->icsk_af_ops)
inet_csk(child)->icsk_af_ops = smc->ori_af_ops; inet_csk(child)->icsk_af_ops = smc->ori_af_ops;
} }
sock_put(&smc->sk);
return child; return child;
drop: drop:
dst_release(dst); dst_release(dst);
tcp_listendrop(sk); tcp_listendrop(sk);
if (smc)
sock_put(&smc->sk);
return NULL; return NULL;
} }
@@ -254,7 +264,7 @@ static void smc_fback_restore_callbacks(struct smc_sock *smc)
struct sock *clcsk = smc->clcsock->sk; struct sock *clcsk = smc->clcsock->sk;
write_lock_bh(&clcsk->sk_callback_lock); 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_state_change, &smc->clcsk_state_change);
smc_clcsock_restore_cb(&clcsk->sk_data_ready, &smc->clcsk_data_ready); 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; struct sock *clcsk = smc->clcsock->sk;
write_lock_bh(&clcsk->sk_callback_lock); 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_clcsock_replace_cb(&clcsk->sk_state_change, smc_fback_state_change,
&smc->clcsk_state_change); &smc->clcsk_state_change);
@@ -2665,8 +2675,8 @@ int smc_listen(struct socket *sock, int backlog)
* smc-specific sk_data_ready function * smc-specific sk_data_ready function
*/ */
write_lock_bh(&smc->clcsock->sk->sk_callback_lock); write_lock_bh(&smc->clcsock->sk->sk_callback_lock);
smc->clcsock->sk->sk_user_data = __rcu_assign_sk_user_data_with_flags(smc->clcsock->sk, smc,
(void *)((uintptr_t)smc | SK_USER_DATA_NOCOPY); SK_USER_DATA_NOCOPY);
smc_clcsock_replace_cb(&smc->clcsock->sk->sk_data_ready, smc_clcsock_replace_cb(&smc->clcsock->sk->sk_data_ready,
smc_clcsock_data_ready, &smc->clcsk_data_ready); smc_clcsock_data_ready, &smc->clcsk_data_ready);
write_unlock_bh(&smc->clcsock->sk->sk_callback_lock); 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); write_lock_bh(&smc->clcsock->sk->sk_callback_lock);
smc_clcsock_restore_cb(&smc->clcsock->sk->sk_data_ready, smc_clcsock_restore_cb(&smc->clcsock->sk->sk_data_ready,
&smc->clcsk_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); write_unlock_bh(&smc->clcsock->sk->sk_callback_lock);
goto out; goto out;
} }
sock_set_flag(sk, SOCK_RCU_FREE);
sk->sk_max_ack_backlog = backlog; sk->sk_max_ack_backlog = backlog;
sk->sk_ack_backlog = 0; sk->sk_ack_backlog = 0;
sk->sk_state = SMC_LISTEN; 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); ((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 */ /* 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 *), static inline void smc_clcsock_replace_cb(void (**target_cb)(struct sock *),
void (*new_cb)(struct sock *), void (*new_cb)(struct sock *),

View File

@@ -218,7 +218,7 @@ again:
write_lock_bh(&smc->clcsock->sk->sk_callback_lock); write_lock_bh(&smc->clcsock->sk->sk_callback_lock);
smc_clcsock_restore_cb(&smc->clcsock->sk->sk_data_ready, smc_clcsock_restore_cb(&smc->clcsock->sk->sk_data_ready,
&smc->clcsk_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); write_unlock_bh(&smc->clcsock->sk->sk_callback_lock);
rc = kernel_sock_shutdown(smc->clcsock, SHUT_RDWR); 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) static void unix_peek_fds(struct scm_cookie *scm, struct sk_buff *skb)
{ {
scm->fp = scm_fp_dup(UNIXCB(skb).fp); scm->fp = scm_fp_dup(UNIXCB(skb).fp);
unix_peek_fpl(scm->fp);
} }
static void unix_destruct_scm(struct sk_buff *skb) 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); void unix_update_edges(struct unix_sock *receiver);
int unix_prepare_fpl(struct scm_fp_list *fpl); int unix_prepare_fpl(struct scm_fp_list *fpl);
void unix_destroy_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); void unix_schedule_gc(struct user_struct *user);
/* SOCK_DIAG */ /* SOCK_DIAG */

View File

@@ -318,6 +318,25 @@ void unix_destroy_fpl(struct scm_fp_list *fpl)
unix_free_vertices(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) static bool unix_vertex_dead(struct unix_vertex *vertex)
{ {
struct unix_edge *edge; struct unix_edge *edge;
@@ -351,6 +370,36 @@ static bool unix_vertex_dead(struct unix_vertex *vertex)
return true; 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) static void unix_collect_skb(struct list_head *scc, struct sk_buff_head *hitlist)
{ {
struct unix_vertex *vertex; struct unix_vertex *vertex;
@@ -404,9 +453,6 @@ static bool unix_scc_cyclic(struct list_head *scc)
return false; 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, static unsigned long __unix_walk_scc(struct unix_vertex *vertex,
unsigned long *last_index, unsigned long *last_index,
struct sk_buff_head *hitlist) struct sk_buff_head *hitlist)
@@ -474,9 +520,7 @@ prev_vertex:
} }
if (vertex->index == vertex->scc_index) { if (vertex->index == vertex->scc_index) {
struct unix_vertex *v;
struct list_head scc; struct list_head scc;
bool scc_dead = true;
/* SCC finalised. /* SCC finalised.
* *
@@ -485,18 +529,7 @@ prev_vertex:
*/ */
__list_cut_position(&scc, &vertex_stack, &vertex->scc_entry); __list_cut_position(&scc, &vertex_stack, &vertex->scc_entry);
list_for_each_entry_reverse(v, &scc, scc_entry) { if (unix_scc_dead(&scc, false)) {
/* 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) {
unix_collect_skb(&scc, hitlist); unix_collect_skb(&scc, hitlist);
} else { } else {
if (unix_vertex_max_scc_index < vertex->scc_index) 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)) { while (!list_empty(&unix_unvisited_vertices)) {
struct unix_vertex *vertex; struct unix_vertex *vertex;
struct list_head scc; struct list_head scc;
bool scc_dead = true;
vertex = list_first_entry(&unix_unvisited_vertices, typeof(*vertex), entry); vertex = list_first_entry(&unix_unvisited_vertices, typeof(*vertex), entry);
list_add(&scc, &vertex->scc_entry); list_add(&scc, &vertex->scc_entry);
list_for_each_entry_reverse(vertex, &scc, scc_entry) { if (unix_scc_dead(&scc, true)) {
list_move_tail(&vertex->entry, &unix_visited_vertices);
if (scc_dead)
scc_dead = unix_vertex_dead(vertex);
}
if (scc_dead) {
cyclic_sccs--; cyclic_sccs--;
unix_collect_skb(&scc, hitlist); 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); cyclic_sccs ? UNIX_GRAPH_CYCLIC : UNIX_GRAPH_NOT_CYCLIC);
} }
static bool gc_in_progress;
static void unix_gc(struct work_struct *work) static void unix_gc(struct work_struct *work)
{ {
struct sk_buff_head hitlist; 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); spin_unlock_bh(&wdev->pmsr_lock);
cancel_work_sync(&wdev->pmsr_free_wk);
if (found) if (found)
cfg80211_pmsr_process_abort(wdev); cfg80211_pmsr_process_abort(wdev);