mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-21 23:16:50 +08:00
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:
@@ -247,8 +247,8 @@ operations:
|
||||
flags: [admin-perm]
|
||||
|
||||
do:
|
||||
pre: net-shaper-nl-pre-doit
|
||||
post: net-shaper-nl-post-doit
|
||||
pre: net-shaper-nl-pre-doit-write
|
||||
post: net-shaper-nl-post-doit-write
|
||||
request:
|
||||
attributes:
|
||||
- ifindex
|
||||
@@ -278,8 +278,8 @@ operations:
|
||||
flags: [admin-perm]
|
||||
|
||||
do:
|
||||
pre: net-shaper-nl-pre-doit
|
||||
post: net-shaper-nl-post-doit
|
||||
pre: net-shaper-nl-pre-doit-write
|
||||
post: net-shaper-nl-post-doit-write
|
||||
request:
|
||||
attributes: *ns-binding
|
||||
|
||||
@@ -309,8 +309,8 @@ operations:
|
||||
flags: [admin-perm]
|
||||
|
||||
do:
|
||||
pre: net-shaper-nl-pre-doit
|
||||
post: net-shaper-nl-post-doit
|
||||
pre: net-shaper-nl-pre-doit-write
|
||||
post: net-shaper-nl-post-doit-write
|
||||
request:
|
||||
attributes:
|
||||
- ifindex
|
||||
|
||||
@@ -787,6 +787,8 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
*/
|
||||
if (soc_type == QCA_WCN3988)
|
||||
rom_ver = ((soc_ver & 0x00000f00) >> 0x05) | (soc_ver & 0x0000000f);
|
||||
else if (soc_type == QCA_WCN3998)
|
||||
rom_ver = ((soc_ver & 0x0000f000) >> 0x07) | (soc_ver & 0x0000000f);
|
||||
else
|
||||
rom_ver = ((soc_ver & 0x00000f00) >> 0x04) | (soc_ver & 0x0000000f);
|
||||
|
||||
|
||||
@@ -257,9 +257,10 @@ static void fwnet_header_cache_update(struct hh_cache *hh,
|
||||
memcpy((u8 *)hh->hh_data + HH_DATA_OFF(FWNET_HLEN), haddr, net->addr_len);
|
||||
}
|
||||
|
||||
static int fwnet_header_parse(const struct sk_buff *skb, unsigned char *haddr)
|
||||
static int fwnet_header_parse(const struct sk_buff *skb, const struct net_device *dev,
|
||||
unsigned char *haddr)
|
||||
{
|
||||
memcpy(haddr, skb->dev->dev_addr, FWNET_ALEN);
|
||||
memcpy(haddr, dev->dev_addr, FWNET_ALEN);
|
||||
|
||||
return FWNET_ALEN;
|
||||
}
|
||||
|
||||
@@ -34,11 +34,17 @@ static int bond_debug_rlb_hash_show(struct seq_file *m, void *v)
|
||||
for (; hash_index != RLB_NULL_INDEX;
|
||||
hash_index = client_info->used_next) {
|
||||
client_info = &(bond_info->rx_hashtbl[hash_index]);
|
||||
seq_printf(m, "%-15pI4 %-15pI4 %-17pM %s\n",
|
||||
&client_info->ip_src,
|
||||
&client_info->ip_dst,
|
||||
&client_info->mac_dst,
|
||||
client_info->slave->dev->name);
|
||||
if (client_info->slave)
|
||||
seq_printf(m, "%-15pI4 %-15pI4 %-17pM %s\n",
|
||||
&client_info->ip_src,
|
||||
&client_info->ip_dst,
|
||||
&client_info->mac_dst,
|
||||
client_info->slave->dev->name);
|
||||
else
|
||||
seq_printf(m, "%-15pI4 %-15pI4 %-17pM (none)\n",
|
||||
&client_info->ip_src,
|
||||
&client_info->ip_dst,
|
||||
&client_info->mac_dst);
|
||||
}
|
||||
|
||||
spin_unlock_bh(&bond->mode_lock);
|
||||
|
||||
@@ -1530,9 +1530,11 @@ static int bond_header_create(struct sk_buff *skb, struct net_device *bond_dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bond_header_parse(const struct sk_buff *skb, unsigned char *haddr)
|
||||
static int bond_header_parse(const struct sk_buff *skb,
|
||||
const struct net_device *dev,
|
||||
unsigned char *haddr)
|
||||
{
|
||||
struct bonding *bond = netdev_priv(skb->dev);
|
||||
struct bonding *bond = netdev_priv(dev);
|
||||
const struct header_ops *slave_ops;
|
||||
struct slave *slave;
|
||||
int ret = 0;
|
||||
@@ -1542,7 +1544,7 @@ static int bond_header_parse(const struct sk_buff *skb, unsigned char *haddr)
|
||||
if (slave) {
|
||||
slave_ops = READ_ONCE(slave->dev->header_ops);
|
||||
if (slave_ops && slave_ops->parse)
|
||||
ret = slave_ops->parse(skb, haddr);
|
||||
ret = slave_ops->parse(skb, slave->dev, haddr);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
|
||||
@@ -980,15 +980,19 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds)
|
||||
ret = bcm_sf2_sw_rst(priv);
|
||||
if (ret) {
|
||||
pr_err("%s: failed to software reset switch\n", __func__);
|
||||
if (!priv->wol_ports_mask)
|
||||
clk_disable_unprepare(priv->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bcm_sf2_crossbar_setup(priv);
|
||||
|
||||
ret = bcm_sf2_cfp_resume(ds);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
if (!priv->wol_ports_mask)
|
||||
clk_disable_unprepare(priv->clk);
|
||||
return ret;
|
||||
|
||||
}
|
||||
if (priv->hw_params.num_gphy == 1)
|
||||
bcm_sf2_gphy_enable_set(ds, true);
|
||||
|
||||
|
||||
@@ -3083,7 +3083,6 @@ static void airoha_remove(struct platform_device *pdev)
|
||||
if (!port)
|
||||
continue;
|
||||
|
||||
airoha_dev_stop(port->dev);
|
||||
unregister_netdev(port->dev);
|
||||
airoha_metadata_dst_free(port);
|
||||
}
|
||||
|
||||
@@ -2929,6 +2929,8 @@ static int bnxt_async_event_process(struct bnxt *bp,
|
||||
u16 type = (u16)BNXT_EVENT_BUF_PRODUCER_TYPE(data1);
|
||||
u32 offset = BNXT_EVENT_BUF_PRODUCER_OFFSET(data2);
|
||||
|
||||
if (type >= ARRAY_SIZE(bp->bs_trace))
|
||||
goto async_event_process_exit;
|
||||
bnxt_bs_trace_check_wrap(&bp->bs_trace[type], offset);
|
||||
goto async_event_process_exit;
|
||||
}
|
||||
|
||||
@@ -2146,7 +2146,7 @@ enum board_idx {
|
||||
};
|
||||
|
||||
#define BNXT_TRACE_BUF_MAGIC_BYTE ((u8)0xbc)
|
||||
#define BNXT_TRACE_MAX 11
|
||||
#define BNXT_TRACE_MAX (DBG_LOG_BUFFER_FLUSH_REQ_TYPE_ERR_QPC_TRACE + 1)
|
||||
|
||||
struct bnxt_bs_trace_info {
|
||||
u8 *magic_byte;
|
||||
|
||||
@@ -123,7 +123,7 @@ static int bcmgenet_poll_wol_status(struct bcmgenet_priv *priv)
|
||||
while (!(bcmgenet_rbuf_readl(priv, RBUF_STATUS)
|
||||
& RBUF_STATUS_WOL)) {
|
||||
retries++;
|
||||
if (retries > 5) {
|
||||
if (retries > 50) {
|
||||
netdev_crit(dev, "polling wol mode timeout\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
@@ -17029,6 +17029,13 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int tg3_is_default_mac_address(u8 *addr)
|
||||
{
|
||||
static const u8 default_mac_address[ETH_ALEN] = { 0x00, 0x10, 0x18, 0x00, 0x00, 0x00 };
|
||||
|
||||
return ether_addr_equal(default_mac_address, addr);
|
||||
}
|
||||
|
||||
static int tg3_get_device_address(struct tg3 *tp, u8 *addr)
|
||||
{
|
||||
u32 hi, lo, mac_offset;
|
||||
@@ -17102,6 +17109,10 @@ static int tg3_get_device_address(struct tg3 *tp, u8 *addr)
|
||||
|
||||
if (!is_valid_ether_addr(addr))
|
||||
return -EINVAL;
|
||||
|
||||
if (tg3_is_default_mac_address(addr))
|
||||
return device_get_mac_address(&tp->pdev->dev, addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -2669,6 +2669,14 @@ static void macb_init_tieoff(struct macb *bp)
|
||||
desc->ctrl = 0;
|
||||
}
|
||||
|
||||
static void gem_init_rx_ring(struct macb_queue *queue)
|
||||
{
|
||||
queue->rx_tail = 0;
|
||||
queue->rx_prepared_head = 0;
|
||||
|
||||
gem_rx_refill(queue);
|
||||
}
|
||||
|
||||
static void gem_init_rings(struct macb *bp)
|
||||
{
|
||||
struct macb_queue *queue;
|
||||
@@ -2686,10 +2694,7 @@ static void gem_init_rings(struct macb *bp)
|
||||
queue->tx_head = 0;
|
||||
queue->tx_tail = 0;
|
||||
|
||||
queue->rx_tail = 0;
|
||||
queue->rx_prepared_head = 0;
|
||||
|
||||
gem_rx_refill(queue);
|
||||
gem_init_rx_ring(queue);
|
||||
}
|
||||
|
||||
macb_init_tieoff(bp);
|
||||
@@ -3978,6 +3983,9 @@ static int gem_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
|
||||
struct macb *bp = netdev_priv(netdev);
|
||||
int ret;
|
||||
|
||||
if (!(netdev->hw_features & NETIF_F_NTUPLE))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
switch (cmd->cmd) {
|
||||
case ETHTOOL_SRXCLSRLINS:
|
||||
if ((cmd->fs.location >= bp->max_tuples)
|
||||
@@ -5947,8 +5955,18 @@ static int __maybe_unused macb_resume(struct device *dev)
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC))
|
||||
macb_init_buffers(bp);
|
||||
|
||||
for (q = 0, queue = bp->queues; q < bp->num_queues;
|
||||
++q, ++queue) {
|
||||
if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC)) {
|
||||
if (macb_is_gem(bp))
|
||||
gem_init_rx_ring(queue);
|
||||
else
|
||||
macb_init_rx_ring(queue);
|
||||
}
|
||||
|
||||
napi_enable(&queue->napi_rx);
|
||||
napi_enable(&queue->napi_tx);
|
||||
}
|
||||
|
||||
@@ -357,8 +357,10 @@ void gem_ptp_remove(struct net_device *ndev)
|
||||
{
|
||||
struct macb *bp = netdev_priv(ndev);
|
||||
|
||||
if (bp->ptp_clock)
|
||||
if (bp->ptp_clock) {
|
||||
ptp_clock_unregister(bp->ptp_clock);
|
||||
bp->ptp_clock = NULL;
|
||||
}
|
||||
|
||||
gem_ptp_clear_timer(bp);
|
||||
|
||||
|
||||
@@ -757,10 +757,13 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter,
|
||||
adapter->num_vlan_filters++;
|
||||
iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER);
|
||||
} else if (f->state == IAVF_VLAN_REMOVE) {
|
||||
/* IAVF_VLAN_REMOVE means that VLAN wasn't yet removed.
|
||||
* We can safely only change the state here.
|
||||
/* Re-add the filter since we cannot tell whether the
|
||||
* pending delete has already been processed by the PF.
|
||||
* A duplicate add is harmless.
|
||||
*/
|
||||
f->state = IAVF_VLAN_ACTIVE;
|
||||
f->state = IAVF_VLAN_ADD;
|
||||
iavf_schedule_aq_request(adapter,
|
||||
IAVF_FLAG_AQ_ADD_VLAN_FILTER);
|
||||
}
|
||||
|
||||
clearout:
|
||||
|
||||
@@ -781,6 +781,8 @@ int igc_ptp_hwtstamp_set(struct net_device *netdev,
|
||||
struct kernel_hwtstamp_config *config,
|
||||
struct netlink_ext_ack *extack);
|
||||
void igc_ptp_tx_hang(struct igc_adapter *adapter);
|
||||
void igc_ptp_clear_xsk_tx_tstamp_queue(struct igc_adapter *adapter,
|
||||
u16 queue_id);
|
||||
void igc_ptp_read(struct igc_adapter *adapter, struct timespec64 *ts);
|
||||
void igc_ptp_tx_tstamp_event(struct igc_adapter *adapter);
|
||||
|
||||
|
||||
@@ -264,6 +264,13 @@ static void igc_clean_tx_ring(struct igc_ring *tx_ring)
|
||||
/* reset next_to_use and next_to_clean */
|
||||
tx_ring->next_to_use = 0;
|
||||
tx_ring->next_to_clean = 0;
|
||||
|
||||
/* Clear any lingering XSK TX timestamp requests */
|
||||
if (test_bit(IGC_RING_FLAG_TX_HWTSTAMP, &tx_ring->flags)) {
|
||||
struct igc_adapter *adapter = netdev_priv(tx_ring->netdev);
|
||||
|
||||
igc_ptp_clear_xsk_tx_tstamp_queue(adapter, tx_ring->queue_index);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1730,11 +1737,8 @@ static netdev_tx_t igc_xmit_frame(struct sk_buff *skb,
|
||||
/* The minimum packet size with TCTL.PSP set is 17 so pad the skb
|
||||
* in order to meet this minimum size requirement.
|
||||
*/
|
||||
if (skb->len < 17) {
|
||||
if (skb_padto(skb, 17))
|
||||
return NETDEV_TX_OK;
|
||||
skb->len = 17;
|
||||
}
|
||||
if (skb_put_padto(skb, 17))
|
||||
return NETDEV_TX_OK;
|
||||
|
||||
return igc_xmit_frame_ring(skb, igc_tx_queue_mapping(adapter, skb));
|
||||
}
|
||||
|
||||
@@ -577,6 +577,39 @@ static void igc_ptp_clear_tx_tstamp(struct igc_adapter *adapter)
|
||||
spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_ptp_clear_xsk_tx_tstamp_queue - Clear pending XSK TX timestamps for a queue
|
||||
* @adapter: Board private structure
|
||||
* @queue_id: TX queue index to clear timestamps for
|
||||
*
|
||||
* Iterates over all TX timestamp registers and releases any pending
|
||||
* timestamp requests associated with the given TX queue. This is
|
||||
* called when an XDP pool is being disabled to ensure no stale
|
||||
* timestamp references remain.
|
||||
*/
|
||||
void igc_ptp_clear_xsk_tx_tstamp_queue(struct igc_adapter *adapter, u16 queue_id)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
spin_lock_irqsave(&adapter->ptp_tx_lock, flags);
|
||||
|
||||
for (i = 0; i < IGC_MAX_TX_TSTAMP_REGS; i++) {
|
||||
struct igc_tx_timestamp_request *tstamp = &adapter->tx_tstamp[i];
|
||||
|
||||
if (tstamp->buffer_type != IGC_TX_BUFFER_TYPE_XSK)
|
||||
continue;
|
||||
if (tstamp->xsk_queue_index != queue_id)
|
||||
continue;
|
||||
if (!tstamp->xsk_tx_buffer)
|
||||
continue;
|
||||
|
||||
igc_ptp_free_tx_buffer(adapter, tstamp);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags);
|
||||
}
|
||||
|
||||
static void igc_ptp_disable_tx_timestamp(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
|
||||
@@ -433,17 +433,21 @@ libie_debugfs_module_write(struct file *filp, const char __user *buf,
|
||||
module = libie_find_module_by_dentry(fwlog->debugfs_modules, dentry);
|
||||
if (module < 0) {
|
||||
dev_info(dev, "unknown module\n");
|
||||
return -EINVAL;
|
||||
count = -EINVAL;
|
||||
goto free_cmd_buf;
|
||||
}
|
||||
|
||||
cnt = sscanf(cmd_buf, "%s", user_val);
|
||||
if (cnt != 1)
|
||||
return -EINVAL;
|
||||
if (cnt != 1) {
|
||||
count = -EINVAL;
|
||||
goto free_cmd_buf;
|
||||
}
|
||||
|
||||
log_level = sysfs_match_string(libie_fwlog_level_string, user_val);
|
||||
if (log_level < 0) {
|
||||
dev_info(dev, "unknown log level '%s'\n", user_val);
|
||||
return -EINVAL;
|
||||
count = -EINVAL;
|
||||
goto free_cmd_buf;
|
||||
}
|
||||
|
||||
if (module != LIBIE_AQC_FW_LOG_ID_MAX) {
|
||||
@@ -458,6 +462,9 @@ libie_debugfs_module_write(struct file *filp, const char __user *buf,
|
||||
fwlog->cfg.module_entries[i].log_level = log_level;
|
||||
}
|
||||
|
||||
free_cmd_buf:
|
||||
kfree(cmd_buf);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -515,23 +522,31 @@ libie_debugfs_nr_messages_write(struct file *filp, const char __user *buf,
|
||||
return PTR_ERR(cmd_buf);
|
||||
|
||||
ret = sscanf(cmd_buf, "%s", user_val);
|
||||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
if (ret != 1) {
|
||||
count = -EINVAL;
|
||||
goto free_cmd_buf;
|
||||
}
|
||||
|
||||
ret = kstrtos16(user_val, 0, &nr_messages);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ret) {
|
||||
count = ret;
|
||||
goto free_cmd_buf;
|
||||
}
|
||||
|
||||
if (nr_messages < LIBIE_AQC_FW_LOG_MIN_RESOLUTION ||
|
||||
nr_messages > LIBIE_AQC_FW_LOG_MAX_RESOLUTION) {
|
||||
dev_err(dev, "Invalid FW log number of messages %d, value must be between %d - %d\n",
|
||||
nr_messages, LIBIE_AQC_FW_LOG_MIN_RESOLUTION,
|
||||
LIBIE_AQC_FW_LOG_MAX_RESOLUTION);
|
||||
return -EINVAL;
|
||||
count = -EINVAL;
|
||||
goto free_cmd_buf;
|
||||
}
|
||||
|
||||
fwlog->cfg.log_resolution = nr_messages;
|
||||
|
||||
free_cmd_buf:
|
||||
kfree(cmd_buf);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -588,8 +603,10 @@ libie_debugfs_enable_write(struct file *filp, const char __user *buf,
|
||||
return PTR_ERR(cmd_buf);
|
||||
|
||||
ret = sscanf(cmd_buf, "%s", user_val);
|
||||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
if (ret != 1) {
|
||||
ret = -EINVAL;
|
||||
goto free_cmd_buf;
|
||||
}
|
||||
|
||||
ret = kstrtobool(user_val, &enable);
|
||||
if (ret)
|
||||
@@ -624,6 +641,8 @@ enable_write_error:
|
||||
*/
|
||||
if (WARN_ON(ret != (ssize_t)count && ret >= 0))
|
||||
ret = -EIO;
|
||||
free_cmd_buf:
|
||||
kfree(cmd_buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -682,8 +701,10 @@ libie_debugfs_log_size_write(struct file *filp, const char __user *buf,
|
||||
return PTR_ERR(cmd_buf);
|
||||
|
||||
ret = sscanf(cmd_buf, "%s", user_val);
|
||||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
if (ret != 1) {
|
||||
ret = -EINVAL;
|
||||
goto free_cmd_buf;
|
||||
}
|
||||
|
||||
index = sysfs_match_string(libie_fwlog_log_size, user_val);
|
||||
if (index < 0) {
|
||||
@@ -712,6 +733,8 @@ log_size_write_error:
|
||||
*/
|
||||
if (WARN_ON(ret != (ssize_t)count && ret >= 0))
|
||||
ret = -EIO;
|
||||
free_cmd_buf:
|
||||
kfree(cmd_buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -5016,7 +5016,7 @@ static int mvpp2_bm_switch_buffers(struct mvpp2 *priv, bool percpu)
|
||||
if (priv->percpu_pools)
|
||||
numbufs = port->nrxqs * 2;
|
||||
|
||||
if (change_percpu)
|
||||
if (change_percpu && priv->global_tx_fc)
|
||||
mvpp2_bm_pool_update_priv_fc(priv, false);
|
||||
|
||||
for (i = 0; i < numbufs; i++)
|
||||
@@ -5041,7 +5041,7 @@ static int mvpp2_bm_switch_buffers(struct mvpp2 *priv, bool percpu)
|
||||
mvpp2_open(port->dev);
|
||||
}
|
||||
|
||||
if (change_percpu)
|
||||
if (change_percpu && priv->global_tx_fc)
|
||||
mvpp2_bm_pool_update_priv_fc(priv, true);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -287,6 +287,7 @@ struct mlx5e_ipsec_sa_entry {
|
||||
struct mlx5e_ipsec_dwork *dwork;
|
||||
struct mlx5e_ipsec_limits limits;
|
||||
u32 rx_mapped_id;
|
||||
u8 ctx[MLX5_ST_SZ_BYTES(ipsec_aso)];
|
||||
};
|
||||
|
||||
struct mlx5_accel_pol_xfrm_attrs {
|
||||
|
||||
@@ -310,10 +310,11 @@ static void mlx5e_ipsec_aso_update(struct mlx5e_ipsec_sa_entry *sa_entry,
|
||||
mlx5e_ipsec_aso_query(sa_entry, data);
|
||||
}
|
||||
|
||||
static void mlx5e_ipsec_update_esn_state(struct mlx5e_ipsec_sa_entry *sa_entry,
|
||||
u32 mode_param)
|
||||
static void
|
||||
mlx5e_ipsec_update_esn_state(struct mlx5e_ipsec_sa_entry *sa_entry,
|
||||
u32 mode_param,
|
||||
struct mlx5_accel_esp_xfrm_attrs *attrs)
|
||||
{
|
||||
struct mlx5_accel_esp_xfrm_attrs attrs = {};
|
||||
struct mlx5_wqe_aso_ctrl_seg data = {};
|
||||
|
||||
if (mode_param < MLX5E_IPSEC_ESN_SCOPE_MID) {
|
||||
@@ -323,18 +324,7 @@ static void mlx5e_ipsec_update_esn_state(struct mlx5e_ipsec_sa_entry *sa_entry,
|
||||
sa_entry->esn_state.overlap = 1;
|
||||
}
|
||||
|
||||
mlx5e_ipsec_build_accel_xfrm_attrs(sa_entry, &attrs);
|
||||
|
||||
/* It is safe to execute the modify below unlocked since the only flows
|
||||
* that could affect this HW object, are create, destroy and this work.
|
||||
*
|
||||
* Creation flow can't co-exist with this modify work, the destruction
|
||||
* flow would cancel this work, and this work is a single entity that
|
||||
* can't conflict with it self.
|
||||
*/
|
||||
spin_unlock_bh(&sa_entry->x->lock);
|
||||
mlx5_accel_esp_modify_xfrm(sa_entry, &attrs);
|
||||
spin_lock_bh(&sa_entry->x->lock);
|
||||
mlx5e_ipsec_build_accel_xfrm_attrs(sa_entry, attrs);
|
||||
|
||||
data.data_offset_condition_operand =
|
||||
MLX5_IPSEC_ASO_REMOVE_FLOW_PKT_CNT_OFFSET;
|
||||
@@ -370,20 +360,18 @@ static void mlx5e_ipsec_aso_update_soft(struct mlx5e_ipsec_sa_entry *sa_entry,
|
||||
static void mlx5e_ipsec_handle_limits(struct mlx5e_ipsec_sa_entry *sa_entry)
|
||||
{
|
||||
struct mlx5_accel_esp_xfrm_attrs *attrs = &sa_entry->attrs;
|
||||
struct mlx5e_ipsec *ipsec = sa_entry->ipsec;
|
||||
struct mlx5e_ipsec_aso *aso = ipsec->aso;
|
||||
bool soft_arm, hard_arm;
|
||||
u64 hard_cnt;
|
||||
|
||||
lockdep_assert_held(&sa_entry->x->lock);
|
||||
|
||||
soft_arm = !MLX5_GET(ipsec_aso, aso->ctx, soft_lft_arm);
|
||||
hard_arm = !MLX5_GET(ipsec_aso, aso->ctx, hard_lft_arm);
|
||||
soft_arm = !MLX5_GET(ipsec_aso, sa_entry->ctx, soft_lft_arm);
|
||||
hard_arm = !MLX5_GET(ipsec_aso, sa_entry->ctx, hard_lft_arm);
|
||||
if (!soft_arm && !hard_arm)
|
||||
/* It is not lifetime event */
|
||||
return;
|
||||
|
||||
hard_cnt = MLX5_GET(ipsec_aso, aso->ctx, remove_flow_pkt_cnt);
|
||||
hard_cnt = MLX5_GET(ipsec_aso, sa_entry->ctx, remove_flow_pkt_cnt);
|
||||
if (!hard_cnt || hard_arm) {
|
||||
/* It is possible to see packet counter equal to zero without
|
||||
* hard limit event armed. Such situation can be if packet
|
||||
@@ -453,11 +441,11 @@ static void mlx5e_ipsec_handle_event(struct work_struct *_work)
|
||||
struct mlx5e_ipsec_work *work =
|
||||
container_of(_work, struct mlx5e_ipsec_work, work);
|
||||
struct mlx5e_ipsec_sa_entry *sa_entry = work->data;
|
||||
struct mlx5_accel_esp_xfrm_attrs tmp = {};
|
||||
struct mlx5_accel_esp_xfrm_attrs *attrs;
|
||||
struct mlx5e_ipsec_aso *aso;
|
||||
bool need_modify = false;
|
||||
int ret;
|
||||
|
||||
aso = sa_entry->ipsec->aso;
|
||||
attrs = &sa_entry->attrs;
|
||||
|
||||
spin_lock_bh(&sa_entry->x->lock);
|
||||
@@ -465,18 +453,22 @@ static void mlx5e_ipsec_handle_event(struct work_struct *_work)
|
||||
if (ret)
|
||||
goto unlock;
|
||||
|
||||
if (attrs->replay_esn.trigger &&
|
||||
!MLX5_GET(ipsec_aso, aso->ctx, esn_event_arm)) {
|
||||
u32 mode_param = MLX5_GET(ipsec_aso, aso->ctx, mode_parameter);
|
||||
|
||||
mlx5e_ipsec_update_esn_state(sa_entry, mode_param);
|
||||
}
|
||||
|
||||
if (attrs->lft.soft_packet_limit != XFRM_INF)
|
||||
mlx5e_ipsec_handle_limits(sa_entry);
|
||||
|
||||
if (attrs->replay_esn.trigger &&
|
||||
!MLX5_GET(ipsec_aso, sa_entry->ctx, esn_event_arm)) {
|
||||
u32 mode_param = MLX5_GET(ipsec_aso, sa_entry->ctx,
|
||||
mode_parameter);
|
||||
|
||||
mlx5e_ipsec_update_esn_state(sa_entry, mode_param, &tmp);
|
||||
need_modify = true;
|
||||
}
|
||||
|
||||
unlock:
|
||||
spin_unlock_bh(&sa_entry->x->lock);
|
||||
if (need_modify)
|
||||
mlx5_accel_esp_modify_xfrm(sa_entry, &tmp);
|
||||
kfree(work);
|
||||
}
|
||||
|
||||
@@ -629,6 +621,8 @@ int mlx5e_ipsec_aso_query(struct mlx5e_ipsec_sa_entry *sa_entry,
|
||||
/* We are in atomic context */
|
||||
udelay(10);
|
||||
} while (ret && time_is_after_jiffies(expires));
|
||||
if (!ret)
|
||||
memcpy(sa_entry->ctx, aso->ctx, MLX5_ST_SZ_BYTES(ipsec_aso));
|
||||
spin_unlock_bh(&aso->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1489,24 +1489,24 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static u32 mlx5_esw_qos_lag_link_speed_get_locked(struct mlx5_core_dev *mdev)
|
||||
static u32 mlx5_esw_qos_lag_link_speed_get(struct mlx5_core_dev *mdev,
|
||||
bool take_rtnl)
|
||||
{
|
||||
struct ethtool_link_ksettings lksettings;
|
||||
struct net_device *slave, *master;
|
||||
u32 speed = SPEED_UNKNOWN;
|
||||
|
||||
/* Lock ensures a stable reference to master and slave netdevice
|
||||
* while port speed of master is queried.
|
||||
*/
|
||||
ASSERT_RTNL();
|
||||
|
||||
slave = mlx5_uplink_netdev_get(mdev);
|
||||
if (!slave)
|
||||
goto out;
|
||||
|
||||
if (take_rtnl)
|
||||
rtnl_lock();
|
||||
master = netdev_master_upper_dev_get(slave);
|
||||
if (master && !__ethtool_get_link_ksettings(master, &lksettings))
|
||||
speed = lksettings.base.speed;
|
||||
if (take_rtnl)
|
||||
rtnl_unlock();
|
||||
|
||||
out:
|
||||
mlx5_uplink_netdev_put(mdev, slave);
|
||||
@@ -1514,20 +1514,15 @@ out:
|
||||
}
|
||||
|
||||
static int mlx5_esw_qos_max_link_speed_get(struct mlx5_core_dev *mdev, u32 *link_speed_max,
|
||||
bool hold_rtnl_lock, struct netlink_ext_ack *extack)
|
||||
bool take_rtnl,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!mlx5_lag_is_active(mdev))
|
||||
goto skip_lag;
|
||||
|
||||
if (hold_rtnl_lock)
|
||||
rtnl_lock();
|
||||
|
||||
*link_speed_max = mlx5_esw_qos_lag_link_speed_get_locked(mdev);
|
||||
|
||||
if (hold_rtnl_lock)
|
||||
rtnl_unlock();
|
||||
*link_speed_max = mlx5_esw_qos_lag_link_speed_get(mdev, take_rtnl);
|
||||
|
||||
if (*link_speed_max != (u32)SPEED_UNKNOWN)
|
||||
return 0;
|
||||
|
||||
@@ -814,9 +814,6 @@ void mana_hwc_destroy_channel(struct gdma_context *gc)
|
||||
gc->max_num_cqs = 0;
|
||||
}
|
||||
|
||||
kfree(hwc->caller_ctx);
|
||||
hwc->caller_ctx = NULL;
|
||||
|
||||
if (hwc->txq)
|
||||
mana_hwc_destroy_wq(hwc, hwc->txq);
|
||||
|
||||
@@ -826,6 +823,9 @@ void mana_hwc_destroy_channel(struct gdma_context *gc)
|
||||
if (hwc->cq)
|
||||
mana_hwc_destroy_cq(hwc->gdma_dev->gdma_context, hwc->cq);
|
||||
|
||||
kfree(hwc->caller_ctx);
|
||||
hwc->caller_ctx = NULL;
|
||||
|
||||
mana_gd_free_res_map(&hwc->inflight_msg_res);
|
||||
|
||||
hwc->num_inflight_msg = 0;
|
||||
|
||||
@@ -1075,6 +1075,11 @@ static int emac_rx_packet(struct prueth_emac *emac, u32 flow_id, u32 *xdp_state)
|
||||
xdp_prepare_buff(&xdp, pa, PRUETH_HEADROOM, pkt_len, false);
|
||||
|
||||
*xdp_state = emac_run_xdp(emac, &xdp, &pkt_len);
|
||||
if (*xdp_state == ICSSG_XDP_CONSUMED) {
|
||||
page_pool_recycle_direct(pool, page);
|
||||
goto requeue;
|
||||
}
|
||||
|
||||
if (*xdp_state != ICSSG_XDP_PASS)
|
||||
goto requeue;
|
||||
headroom = xdp.data - xdp.data_hard_start;
|
||||
|
||||
@@ -109,8 +109,11 @@ static int nsim_forward_skb(struct net_device *tx_dev,
|
||||
int ret;
|
||||
|
||||
ret = __dev_forward_skb(rx_dev, skb);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
if (psp_ext)
|
||||
__skb_ext_put(psp_ext);
|
||||
return ret;
|
||||
}
|
||||
|
||||
nsim_psp_handle_ext(skb, psp_ext);
|
||||
|
||||
|
||||
@@ -1395,14 +1395,14 @@ static int aqc111_suspend(struct usb_interface *intf, pm_message_t message)
|
||||
aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC,
|
||||
SFR_MEDIUM_STATUS_MODE, 2, ®16);
|
||||
|
||||
aqc111_write_cmd(dev, AQ_WOL_CFG, 0, 0,
|
||||
WOL_CFG_SIZE, &wol_cfg);
|
||||
aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0,
|
||||
&aqc111_data->phy_cfg);
|
||||
aqc111_write_cmd_nopm(dev, AQ_WOL_CFG, 0, 0,
|
||||
WOL_CFG_SIZE, &wol_cfg);
|
||||
aqc111_write32_cmd_nopm(dev, AQ_PHY_OPS, 0, 0,
|
||||
&aqc111_data->phy_cfg);
|
||||
} else {
|
||||
aqc111_data->phy_cfg |= AQ_LOW_POWER;
|
||||
aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0,
|
||||
&aqc111_data->phy_cfg);
|
||||
aqc111_write32_cmd_nopm(dev, AQ_PHY_OPS, 0, 0,
|
||||
&aqc111_data->phy_cfg);
|
||||
|
||||
/* Disable RX path */
|
||||
aqc111_read16_cmd_nopm(dev, AQ_ACCESS_MAC,
|
||||
|
||||
@@ -1656,6 +1656,7 @@ int cdc_ncm_rx_verify_ndp16(struct sk_buff *skb_in, int ndpoffset)
|
||||
struct usbnet *dev = netdev_priv(skb_in->dev);
|
||||
struct usb_cdc_ncm_ndp16 *ndp16;
|
||||
int ret = -EINVAL;
|
||||
size_t ndp_len;
|
||||
|
||||
if ((ndpoffset + sizeof(struct usb_cdc_ncm_ndp16)) > skb_in->len) {
|
||||
netif_dbg(dev, rx_err, dev->net, "invalid NDP offset <%u>\n",
|
||||
@@ -1675,8 +1676,8 @@ int cdc_ncm_rx_verify_ndp16(struct sk_buff *skb_in, int ndpoffset)
|
||||
sizeof(struct usb_cdc_ncm_dpe16));
|
||||
ret--; /* we process NDP entries except for the last one */
|
||||
|
||||
if ((sizeof(struct usb_cdc_ncm_ndp16) +
|
||||
ret * (sizeof(struct usb_cdc_ncm_dpe16))) > skb_in->len) {
|
||||
ndp_len = struct_size_t(struct usb_cdc_ncm_ndp16, dpe16, ret);
|
||||
if (ndpoffset + ndp_len > skb_in->len) {
|
||||
netif_dbg(dev, rx_err, dev->net, "Invalid nframes = %d\n", ret);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
@@ -1692,6 +1693,7 @@ int cdc_ncm_rx_verify_ndp32(struct sk_buff *skb_in, int ndpoffset)
|
||||
struct usbnet *dev = netdev_priv(skb_in->dev);
|
||||
struct usb_cdc_ncm_ndp32 *ndp32;
|
||||
int ret = -EINVAL;
|
||||
size_t ndp_len;
|
||||
|
||||
if ((ndpoffset + sizeof(struct usb_cdc_ncm_ndp32)) > skb_in->len) {
|
||||
netif_dbg(dev, rx_err, dev->net, "invalid NDP offset <%u>\n",
|
||||
@@ -1711,8 +1713,8 @@ int cdc_ncm_rx_verify_ndp32(struct sk_buff *skb_in, int ndpoffset)
|
||||
sizeof(struct usb_cdc_ncm_dpe32));
|
||||
ret--; /* we process NDP entries except for the last one */
|
||||
|
||||
if ((sizeof(struct usb_cdc_ncm_ndp32) +
|
||||
ret * (sizeof(struct usb_cdc_ncm_dpe32))) > skb_in->len) {
|
||||
ndp_len = struct_size_t(struct usb_cdc_ncm_ndp32, dpe32, ret);
|
||||
if (ndpoffset + ndp_len > skb_in->len) {
|
||||
netif_dbg(dev, rx_err, dev->net, "Invalid nframes = %d\n", ret);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
@@ -1006,7 +1006,7 @@ static void ath_scan_send_probe(struct ath_softc *sc,
|
||||
skb_set_queue_mapping(skb, IEEE80211_AC_VO);
|
||||
|
||||
if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, NULL))
|
||||
goto error;
|
||||
return;
|
||||
|
||||
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
|
||||
if (ath_tx_start(sc->hw, skb, &txctl))
|
||||
@@ -1119,10 +1119,8 @@ ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
|
||||
|
||||
skb->priority = 7;
|
||||
skb_set_queue_mapping(skb, IEEE80211_AC_VO);
|
||||
if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) {
|
||||
dev_kfree_skb_any(skb);
|
||||
if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta))
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
|
||||
@@ -63,10 +63,8 @@ mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid)
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
if (!ieee80211_tx_prepare_skb(phy->hw, vif, skb, band, NULL)) {
|
||||
ieee80211_free_txskb(phy->hw, skb);
|
||||
if (!ieee80211_tx_prepare_skb(phy->hw, vif, skb, band, NULL))
|
||||
goto out;
|
||||
}
|
||||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
if (req->no_cck)
|
||||
|
||||
@@ -210,7 +210,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
if (skb_headroom(skb) < (total_len - skb->len) &&
|
||||
pskb_expand_head(skb, (total_len - skb->len), 0, GFP_ATOMIC)) {
|
||||
wl1271_free_tx_id(wl, id);
|
||||
return -EAGAIN;
|
||||
return -ENOMEM;
|
||||
}
|
||||
desc = skb_push(skb, total_len - skb->len);
|
||||
|
||||
|
||||
@@ -3021,7 +3021,6 @@ static void hw_scan_work(struct work_struct *work)
|
||||
hwsim->tmp_chan->band,
|
||||
NULL)) {
|
||||
rcu_read_unlock();
|
||||
kfree_skb(probe);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -6489,7 +6488,7 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
|
||||
if (info->attrs[HWSIM_ATTR_PMSR_SUPPORT]) {
|
||||
struct cfg80211_pmsr_capabilities *pmsr_capa;
|
||||
|
||||
pmsr_capa = kmalloc_obj(*pmsr_capa);
|
||||
pmsr_capa = kzalloc_obj(*pmsr_capa);
|
||||
if (!pmsr_capa) {
|
||||
ret = -ENOMEM;
|
||||
goto out_free;
|
||||
|
||||
@@ -47,8 +47,8 @@ static int nxp_nci_i2c_set_mode(void *phy_id,
|
||||
{
|
||||
struct nxp_nci_i2c_phy *phy = (struct nxp_nci_i2c_phy *) phy_id;
|
||||
|
||||
gpiod_set_value(phy->gpiod_fw, (mode == NXP_NCI_MODE_FW) ? 1 : 0);
|
||||
gpiod_set_value(phy->gpiod_en, (mode != NXP_NCI_MODE_COLD) ? 1 : 0);
|
||||
gpiod_set_value_cansleep(phy->gpiod_fw, (mode == NXP_NCI_MODE_FW) ? 1 : 0);
|
||||
gpiod_set_value_cansleep(phy->gpiod_en, (mode != NXP_NCI_MODE_COLD) ? 1 : 0);
|
||||
usleep_range(10000, 15000);
|
||||
|
||||
if (mode == NXP_NCI_MODE_COLD)
|
||||
|
||||
@@ -42,7 +42,8 @@ extern const struct header_ops eth_header_ops;
|
||||
|
||||
int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
|
||||
const void *daddr, const void *saddr, unsigned len);
|
||||
int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr);
|
||||
int eth_header_parse(const struct sk_buff *skb, const struct net_device *dev,
|
||||
unsigned char *haddr);
|
||||
int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh,
|
||||
__be16 type);
|
||||
void eth_header_cache_update(struct hh_cache *hh, const struct net_device *dev,
|
||||
|
||||
@@ -40,7 +40,8 @@ static inline struct ethhdr *inner_eth_hdr(const struct sk_buff *skb)
|
||||
return (struct ethhdr *)skb_inner_mac_header(skb);
|
||||
}
|
||||
|
||||
int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr);
|
||||
int eth_header_parse(const struct sk_buff *skb, const struct net_device *dev,
|
||||
unsigned char *haddr);
|
||||
|
||||
extern ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len);
|
||||
|
||||
|
||||
@@ -311,7 +311,9 @@ struct header_ops {
|
||||
int (*create) (struct sk_buff *skb, struct net_device *dev,
|
||||
unsigned short type, const void *daddr,
|
||||
const void *saddr, unsigned int len);
|
||||
int (*parse)(const struct sk_buff *skb, unsigned char *haddr);
|
||||
int (*parse)(const struct sk_buff *skb,
|
||||
const struct net_device *dev,
|
||||
unsigned char *haddr);
|
||||
int (*cache)(const struct neighbour *neigh, struct hh_cache *hh, __be16 type);
|
||||
void (*cache_update)(struct hh_cache *hh,
|
||||
const struct net_device *dev,
|
||||
@@ -2155,6 +2157,7 @@ struct net_device {
|
||||
unsigned long state;
|
||||
unsigned int flags;
|
||||
unsigned short hard_header_len;
|
||||
enum netdev_stat_type pcpu_stat_type:8;
|
||||
netdev_features_t features;
|
||||
struct inet6_dev __rcu *ip6_ptr;
|
||||
__cacheline_group_end(net_device_read_txrx);
|
||||
@@ -2404,8 +2407,6 @@ struct net_device {
|
||||
void *ml_priv;
|
||||
enum netdev_ml_priv_type ml_priv_type;
|
||||
|
||||
enum netdev_stat_type pcpu_stat_type:8;
|
||||
|
||||
#if IS_ENABLED(CONFIG_GARP)
|
||||
struct garp_port __rcu *garp_port;
|
||||
#endif
|
||||
@@ -3446,7 +3447,7 @@ static inline int dev_parse_header(const struct sk_buff *skb,
|
||||
|
||||
if (!dev->header_ops || !dev->header_ops->parse)
|
||||
return 0;
|
||||
return dev->header_ops->parse(skb, haddr);
|
||||
return dev->header_ops->parse(skb, dev, haddr);
|
||||
}
|
||||
|
||||
static inline __be16 dev_parse_header_protocol(const struct sk_buff *skb)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
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_add(&tstats->tx_bytes, pkt_len);
|
||||
u64_stats_inc(&tstats->tx_packets);
|
||||
u64_stats_update_end(&tstats->syncp);
|
||||
put_cpu_ptr(tstats);
|
||||
u64_stats_update_begin(&dstats->syncp);
|
||||
u64_stats_add(&dstats->tx_bytes, pkt_len);
|
||||
u64_stats_inc(&dstats->tx_packets);
|
||||
u64_stats_update_end(&dstats->syncp);
|
||||
put_cpu_ptr(dstats);
|
||||
return;
|
||||
}
|
||||
if (dev->pcpu_stat_type == NETDEV_PCPU_STAT_TSTATS) {
|
||||
struct pcpu_sw_netstats *tstats = get_cpu_ptr(dev->tstats);
|
||||
|
||||
u64_stats_update_begin(&tstats->syncp);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -7407,7 +7407,9 @@ void ieee80211_report_wowlan_wakeup(struct ieee80211_vif *vif,
|
||||
* @band: the band to transmit on
|
||||
* @sta: optional pointer to get the station to send the frame to
|
||||
*
|
||||
* Return: %true if the skb was prepared, %false otherwise
|
||||
* Return: %true if the skb was prepared, %false otherwise.
|
||||
* On failure, the skb is freed by this function; callers must not
|
||||
* free it again.
|
||||
*
|
||||
* Note: must be called under RCU lock
|
||||
*/
|
||||
|
||||
@@ -277,8 +277,6 @@ struct nft_userdata {
|
||||
unsigned char data[];
|
||||
};
|
||||
|
||||
#define NFT_SET_ELEM_INTERNAL_LAST 0x1
|
||||
|
||||
/* placeholder structure for opaque set element backend representation. */
|
||||
struct nft_elem_priv { };
|
||||
|
||||
@@ -288,7 +286,6 @@ struct nft_elem_priv { };
|
||||
* @key: element key
|
||||
* @key_end: closing element key
|
||||
* @data: element data
|
||||
* @flags: flags
|
||||
* @priv: element private data and extensions
|
||||
*/
|
||||
struct nft_set_elem {
|
||||
@@ -304,7 +301,6 @@ struct nft_set_elem {
|
||||
u32 buf[NFT_DATA_VALUE_MAXLEN / sizeof(u32)];
|
||||
struct nft_data val;
|
||||
} data;
|
||||
u32 flags;
|
||||
struct nft_elem_priv *priv;
|
||||
};
|
||||
|
||||
@@ -878,6 +874,8 @@ struct nft_elem_priv *nft_set_elem_init(const struct nft_set *set,
|
||||
u64 timeout, u64 expiration, gfp_t gfp);
|
||||
int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set,
|
||||
struct nft_expr *expr_array[]);
|
||||
void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
|
||||
struct nft_set_elem_expr *elem_expr);
|
||||
void nft_set_elem_destroy(const struct nft_set *set,
|
||||
const struct nft_elem_priv *elem_priv,
|
||||
bool destroy_expr);
|
||||
|
||||
@@ -716,6 +716,34 @@ void qdisc_destroy(struct Qdisc *qdisc);
|
||||
void qdisc_put(struct Qdisc *qdisc);
|
||||
void qdisc_put_unlocked(struct Qdisc *qdisc);
|
||||
void qdisc_tree_reduce_backlog(struct Qdisc *qdisc, int n, int len);
|
||||
|
||||
static inline void dev_reset_queue(struct net_device *dev,
|
||||
struct netdev_queue *dev_queue,
|
||||
void *_unused)
|
||||
{
|
||||
struct Qdisc *qdisc;
|
||||
bool nolock;
|
||||
|
||||
qdisc = rtnl_dereference(dev_queue->qdisc_sleeping);
|
||||
if (!qdisc)
|
||||
return;
|
||||
|
||||
nolock = qdisc->flags & TCQ_F_NOLOCK;
|
||||
|
||||
if (nolock)
|
||||
spin_lock_bh(&qdisc->seqlock);
|
||||
spin_lock_bh(qdisc_lock(qdisc));
|
||||
|
||||
qdisc_reset(qdisc);
|
||||
|
||||
spin_unlock_bh(qdisc_lock(qdisc));
|
||||
if (nolock) {
|
||||
clear_bit(__QDISC_STATE_MISSED, &qdisc->state);
|
||||
clear_bit(__QDISC_STATE_DRAINING, &qdisc->state);
|
||||
spin_unlock_bh(&qdisc->seqlock);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_SCHED
|
||||
int qdisc_offload_dump_helper(struct Qdisc *q, enum tc_setup_type type,
|
||||
void *type_data);
|
||||
@@ -1429,6 +1457,11 @@ void mini_qdisc_pair_init(struct mini_Qdisc_pair *miniqp, struct Qdisc *qdisc,
|
||||
void mini_qdisc_pair_block_init(struct mini_Qdisc_pair *miniqp,
|
||||
struct tcf_block *block);
|
||||
|
||||
static inline bool mini_qdisc_pair_inited(struct mini_Qdisc_pair *miniqp)
|
||||
{
|
||||
return !!miniqp->p_miniq;
|
||||
}
|
||||
|
||||
void mq_change_real_num_tx(struct Qdisc *sch, unsigned int new_real_tx);
|
||||
|
||||
int sch_frag_xmit_hook(struct sk_buff *skb, int (*xmit)(struct sk_buff *skb));
|
||||
|
||||
@@ -52,7 +52,7 @@ int udp_sock_create6(struct net *net, struct udp_port_cfg *cfg,
|
||||
static inline int udp_sock_create6(struct net *net, struct udp_port_cfg *cfg,
|
||||
struct socket **sockp)
|
||||
{
|
||||
return 0;
|
||||
return -EPFNOSUPPORT;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -154,10 +154,19 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
|
||||
/* 0x01 is topology change */
|
||||
|
||||
priv = netdev_priv(dev);
|
||||
atm_force_charge(priv->lecd, skb2->truesize);
|
||||
sk = sk_atm(priv->lecd);
|
||||
skb_queue_tail(&sk->sk_receive_queue, skb2);
|
||||
sk->sk_data_ready(sk);
|
||||
struct atm_vcc *vcc;
|
||||
|
||||
rcu_read_lock();
|
||||
vcc = rcu_dereference(priv->lecd);
|
||||
if (vcc) {
|
||||
atm_force_charge(vcc, skb2->truesize);
|
||||
sk = sk_atm(vcc);
|
||||
skb_queue_tail(&sk->sk_receive_queue, skb2);
|
||||
sk->sk_data_ready(sk);
|
||||
} else {
|
||||
dev_kfree_skb(skb2);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
}
|
||||
#endif /* IS_ENABLED(CONFIG_BRIDGE) */
|
||||
@@ -216,7 +225,7 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
|
||||
int is_rdesc;
|
||||
|
||||
pr_debug("called\n");
|
||||
if (!priv->lecd) {
|
||||
if (!rcu_access_pointer(priv->lecd)) {
|
||||
pr_info("%s:No lecd attached\n", dev->name);
|
||||
dev->stats.tx_errors++;
|
||||
netif_stop_queue(dev);
|
||||
@@ -449,10 +458,19 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
|
||||
break;
|
||||
skb2->len = sizeof(struct atmlec_msg);
|
||||
skb_copy_to_linear_data(skb2, mesg, sizeof(*mesg));
|
||||
atm_force_charge(priv->lecd, skb2->truesize);
|
||||
sk = sk_atm(priv->lecd);
|
||||
skb_queue_tail(&sk->sk_receive_queue, skb2);
|
||||
sk->sk_data_ready(sk);
|
||||
struct atm_vcc *vcc;
|
||||
|
||||
rcu_read_lock();
|
||||
vcc = rcu_dereference(priv->lecd);
|
||||
if (vcc) {
|
||||
atm_force_charge(vcc, skb2->truesize);
|
||||
sk = sk_atm(vcc);
|
||||
skb_queue_tail(&sk->sk_receive_queue, skb2);
|
||||
sk->sk_data_ready(sk);
|
||||
} else {
|
||||
dev_kfree_skb(skb2);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
}
|
||||
#endif /* IS_ENABLED(CONFIG_BRIDGE) */
|
||||
@@ -468,23 +486,16 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
|
||||
|
||||
static void lec_atm_close(struct atm_vcc *vcc)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct net_device *dev = (struct net_device *)vcc->proto_data;
|
||||
struct lec_priv *priv = netdev_priv(dev);
|
||||
|
||||
priv->lecd = NULL;
|
||||
rcu_assign_pointer(priv->lecd, NULL);
|
||||
synchronize_rcu();
|
||||
/* Do something needful? */
|
||||
|
||||
netif_stop_queue(dev);
|
||||
lec_arp_destroy(priv);
|
||||
|
||||
if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
|
||||
pr_info("%s closing with messages pending\n", dev->name);
|
||||
while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue))) {
|
||||
atm_return(vcc, skb->truesize);
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
pr_info("%s: Shut down!\n", dev->name);
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
@@ -510,12 +521,14 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
|
||||
const unsigned char *mac_addr, const unsigned char *atm_addr,
|
||||
struct sk_buff *data)
|
||||
{
|
||||
struct atm_vcc *vcc;
|
||||
struct sock *sk;
|
||||
struct sk_buff *skb;
|
||||
struct atmlec_msg *mesg;
|
||||
|
||||
if (!priv || !priv->lecd)
|
||||
if (!priv || !rcu_access_pointer(priv->lecd))
|
||||
return -1;
|
||||
|
||||
skb = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
|
||||
if (!skb)
|
||||
return -1;
|
||||
@@ -532,18 +545,27 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
|
||||
if (atm_addr)
|
||||
memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN);
|
||||
|
||||
atm_force_charge(priv->lecd, skb->truesize);
|
||||
sk = sk_atm(priv->lecd);
|
||||
rcu_read_lock();
|
||||
vcc = rcu_dereference(priv->lecd);
|
||||
if (!vcc) {
|
||||
rcu_read_unlock();
|
||||
kfree_skb(skb);
|
||||
return -1;
|
||||
}
|
||||
|
||||
atm_force_charge(vcc, skb->truesize);
|
||||
sk = sk_atm(vcc);
|
||||
skb_queue_tail(&sk->sk_receive_queue, skb);
|
||||
sk->sk_data_ready(sk);
|
||||
|
||||
if (data != NULL) {
|
||||
pr_debug("about to send %d bytes of data\n", data->len);
|
||||
atm_force_charge(priv->lecd, data->truesize);
|
||||
atm_force_charge(vcc, data->truesize);
|
||||
skb_queue_tail(&sk->sk_receive_queue, data);
|
||||
sk->sk_data_ready(sk);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -618,7 +640,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
|
||||
|
||||
atm_return(vcc, skb->truesize);
|
||||
if (*(__be16 *) skb->data == htons(priv->lecid) ||
|
||||
!priv->lecd || !(dev->flags & IFF_UP)) {
|
||||
!rcu_access_pointer(priv->lecd) || !(dev->flags & IFF_UP)) {
|
||||
/*
|
||||
* Probably looping back, or if lecd is missing,
|
||||
* lecd has gone down
|
||||
@@ -753,12 +775,12 @@ static int lecd_attach(struct atm_vcc *vcc, int arg)
|
||||
priv = netdev_priv(dev_lec[i]);
|
||||
} else {
|
||||
priv = netdev_priv(dev_lec[i]);
|
||||
if (priv->lecd)
|
||||
if (rcu_access_pointer(priv->lecd))
|
||||
return -EADDRINUSE;
|
||||
}
|
||||
lec_arp_init(priv);
|
||||
priv->itfnum = i; /* LANE2 addition */
|
||||
priv->lecd = vcc;
|
||||
rcu_assign_pointer(priv->lecd, vcc);
|
||||
vcc->dev = &lecatm_dev;
|
||||
vcc_insert_socket(sk_atm(vcc));
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ struct lec_priv {
|
||||
*/
|
||||
spinlock_t lec_arp_lock;
|
||||
struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */
|
||||
struct atm_vcc *lecd;
|
||||
struct atm_vcc __rcu *lecd;
|
||||
struct delayed_work lec_arp_work; /* C10 */
|
||||
unsigned int maximum_unknown_frame_count;
|
||||
/*
|
||||
|
||||
@@ -473,6 +473,9 @@ batadv_iv_ogm_can_aggregate(const struct batadv_ogm_packet *new_bat_ogm_packet,
|
||||
if (aggregated_bytes > max_bytes)
|
||||
return false;
|
||||
|
||||
if (skb_tailroom(forw_packet->skb) < packet_len)
|
||||
return false;
|
||||
|
||||
if (packet_num >= BATADV_MAX_AGGREGATION_PACKETS)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -1944,6 +1944,8 @@ static bool hci_le_set_cig_params(struct hci_conn *conn, struct bt_iso_qos *qos)
|
||||
return false;
|
||||
|
||||
done:
|
||||
conn->iso_qos = *qos;
|
||||
|
||||
if (hci_cmd_sync_queue(hdev, set_cig_params_sync,
|
||||
UINT_PTR(qos->ucast.cig), NULL) < 0)
|
||||
return false;
|
||||
@@ -2013,8 +2015,6 @@ struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
}
|
||||
|
||||
hci_conn_hold(cis);
|
||||
|
||||
cis->iso_qos = *qos;
|
||||
cis->state = BT_BOUND;
|
||||
|
||||
return cis;
|
||||
|
||||
@@ -6627,8 +6627,8 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)
|
||||
* state.
|
||||
*/
|
||||
if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
|
||||
hci_scan_disable_sync(hdev);
|
||||
hci_dev_set_flag(hdev, HCI_LE_SCAN_INTERRUPTED);
|
||||
hci_scan_disable_sync(hdev);
|
||||
}
|
||||
|
||||
/* Update random address, but set require_privacy to false so
|
||||
|
||||
@@ -986,7 +986,8 @@ static void session_free(struct kref *ref)
|
||||
skb_queue_purge(&session->intr_transmit);
|
||||
fput(session->intr_sock->file);
|
||||
fput(session->ctrl_sock->file);
|
||||
l2cap_conn_put(session->conn);
|
||||
if (session->conn)
|
||||
l2cap_conn_put(session->conn);
|
||||
kfree(session);
|
||||
}
|
||||
|
||||
@@ -1164,6 +1165,15 @@ static void hidp_session_remove(struct l2cap_conn *conn,
|
||||
|
||||
down_write(&hidp_session_sem);
|
||||
|
||||
/* Drop L2CAP reference immediately to indicate that
|
||||
* l2cap_unregister_user() shall not be called as it is already
|
||||
* considered removed.
|
||||
*/
|
||||
if (session->conn) {
|
||||
l2cap_conn_put(session->conn);
|
||||
session->conn = NULL;
|
||||
}
|
||||
|
||||
hidp_session_terminate(session);
|
||||
|
||||
cancel_work_sync(&session->dev_init);
|
||||
@@ -1301,7 +1311,9 @@ static int hidp_session_thread(void *arg)
|
||||
* Instead, this call has the same semantics as if user-space tried to
|
||||
* delete the session.
|
||||
*/
|
||||
l2cap_unregister_user(session->conn, &session->user);
|
||||
if (session->conn)
|
||||
l2cap_unregister_user(session->conn, &session->user);
|
||||
|
||||
hidp_session_put(session);
|
||||
|
||||
module_put_and_kthread_exit(0);
|
||||
|
||||
@@ -1678,17 +1678,15 @@ static void l2cap_info_timeout(struct work_struct *work)
|
||||
|
||||
int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user)
|
||||
{
|
||||
struct hci_dev *hdev = conn->hcon->hdev;
|
||||
int ret;
|
||||
|
||||
/* We need to check whether l2cap_conn is registered. If it is not, we
|
||||
* must not register the l2cap_user. l2cap_conn_del() is unregisters
|
||||
* l2cap_conn objects, but doesn't provide its own locking. Instead, it
|
||||
* relies on the parent hci_conn object to be locked. This itself relies
|
||||
* on the hci_dev object to be locked. So we must lock the hci device
|
||||
* here, too. */
|
||||
* must not register the l2cap_user. l2cap_conn_del() unregisters
|
||||
* l2cap_conn objects under conn->lock, and we use the same lock here
|
||||
* to protect access to conn->users and conn->hchan.
|
||||
*/
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
mutex_lock(&conn->lock);
|
||||
|
||||
if (!list_empty(&user->list)) {
|
||||
ret = -EINVAL;
|
||||
@@ -1709,16 +1707,14 @@ int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user)
|
||||
ret = 0;
|
||||
|
||||
out_unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
mutex_unlock(&conn->lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(l2cap_register_user);
|
||||
|
||||
void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user)
|
||||
{
|
||||
struct hci_dev *hdev = conn->hcon->hdev;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
mutex_lock(&conn->lock);
|
||||
|
||||
if (list_empty(&user->list))
|
||||
goto out_unlock;
|
||||
@@ -1727,7 +1723,7 @@ void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user)
|
||||
user->remove(conn, user);
|
||||
|
||||
out_unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
mutex_unlock(&conn->lock);
|
||||
}
|
||||
EXPORT_SYMBOL(l2cap_unregister_user);
|
||||
|
||||
@@ -4616,7 +4612,8 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn,
|
||||
|
||||
switch (type) {
|
||||
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) {
|
||||
struct l2cap_info_req req;
|
||||
@@ -4635,7 +4632,8 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn,
|
||||
break;
|
||||
|
||||
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_ident = 0;
|
||||
|
||||
@@ -5059,7 +5057,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
|
||||
u16 mtu, mps;
|
||||
__le16 psm;
|
||||
u8 result, rsp_len = 0;
|
||||
int i, num_scid;
|
||||
int i, num_scid = 0;
|
||||
bool defer = false;
|
||||
|
||||
if (!enable_ecred)
|
||||
@@ -5072,6 +5070,14 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
|
||||
goto response;
|
||||
}
|
||||
|
||||
/* Check if there are no pending channels with the same ident */
|
||||
__l2cap_chan_list_id(conn, cmd->ident, l2cap_ecred_list_defer,
|
||||
&num_scid);
|
||||
if (num_scid) {
|
||||
result = L2CAP_CR_LE_INVALID_PARAMS;
|
||||
goto response;
|
||||
}
|
||||
|
||||
cmd_len -= sizeof(*req);
|
||||
num_scid = cmd_len / sizeof(u16);
|
||||
|
||||
@@ -5424,7 +5430,7 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn,
|
||||
u8 *data)
|
||||
{
|
||||
struct l2cap_chan *chan, *tmp;
|
||||
struct l2cap_ecred_conn_rsp *rsp = (void *) data;
|
||||
struct l2cap_ecred_reconf_rsp *rsp = (void *)data;
|
||||
u16 result;
|
||||
|
||||
if (cmd_len < sizeof(*rsp))
|
||||
@@ -5432,7 +5438,7 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn,
|
||||
|
||||
result = __le16_to_cpu(rsp->result);
|
||||
|
||||
BT_DBG("result 0x%4.4x", rsp->result);
|
||||
BT_DBG("result 0x%4.4x", result);
|
||||
|
||||
if (!result)
|
||||
return 0;
|
||||
@@ -6662,8 +6668,10 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
if (chan->imtu < skb->len) {
|
||||
BT_ERR("Too big LE L2CAP PDU");
|
||||
if (skb->len > chan->imtu) {
|
||||
BT_ERR("Too big LE L2CAP PDU: len %u > %u", skb->len,
|
||||
chan->imtu);
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
@@ -6689,7 +6697,9 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
|
||||
sdu_len, skb->len, chan->imtu);
|
||||
|
||||
if (sdu_len > chan->imtu) {
|
||||
BT_ERR("Too big LE L2CAP SDU length received");
|
||||
BT_ERR("Too big LE L2CAP SDU length: len %u > %u",
|
||||
skb->len, sdu_len);
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
err = -EMSGSIZE;
|
||||
goto failed;
|
||||
}
|
||||
@@ -6725,6 +6735,7 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
|
||||
|
||||
if (chan->sdu->len + skb->len > chan->sdu_len) {
|
||||
BT_ERR("Too much LE L2CAP data received");
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
err = -EINVAL;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
@@ -2195,10 +2195,7 @@ static void set_mesh_complete(struct hci_dev *hdev, void *data, int err)
|
||||
sk = cmd->sk;
|
||||
|
||||
if (status) {
|
||||
mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER,
|
||||
status);
|
||||
mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev, true,
|
||||
cmd_status_rsp, &status);
|
||||
mgmt_cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -5377,7 +5374,7 @@ static void mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev,
|
||||
|
||||
mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
|
||||
mgmt_status(status), &rp, sizeof(rp));
|
||||
mgmt_pending_remove(cmd);
|
||||
mgmt_pending_free(cmd);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
bt_dev_dbg(hdev, "add monitor %d complete, status %d",
|
||||
|
||||
@@ -2743,7 +2743,7 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
if (!test_bit(SMP_FLAG_DEBUG_KEY, &smp->flags) &&
|
||||
!crypto_memneq(key, smp->local_pk, 64)) {
|
||||
bt_dev_err(hdev, "Remote and local public keys are identical");
|
||||
return SMP_UNSPECIFIED;
|
||||
return SMP_DHKEY_CHECK_FAILED;
|
||||
}
|
||||
|
||||
memcpy(smp->remote_pk, key, 64);
|
||||
|
||||
@@ -576,7 +576,7 @@ static void mep_delete_implementation(struct net_bridge *br,
|
||||
|
||||
/* Empty and free peer MEP list */
|
||||
hlist_for_each_entry_safe(peer_mep, n_store, &mep->peer_mep_list, head) {
|
||||
cancel_delayed_work_sync(&peer_mep->ccm_rx_dwork);
|
||||
disable_delayed_work_sync(&peer_mep->ccm_rx_dwork);
|
||||
hlist_del_rcu(&peer_mep->head);
|
||||
kfree_rcu(peer_mep, rcu);
|
||||
}
|
||||
@@ -732,7 +732,7 @@ int br_cfm_cc_peer_mep_remove(struct net_bridge *br, const u32 instance,
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
cc_peer_disable(peer_mep);
|
||||
disable_delayed_work_sync(&peer_mep->ccm_rx_dwork);
|
||||
|
||||
hlist_del_rcu(&peer_mep->head);
|
||||
kfree_rcu(peer_mep, rcu);
|
||||
|
||||
@@ -193,14 +193,11 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL(eth_type_trans);
|
||||
|
||||
/**
|
||||
* eth_header_parse - extract hardware address from packet
|
||||
* @skb: packet to extract header from
|
||||
* @haddr: destination buffer
|
||||
*/
|
||||
int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr)
|
||||
int eth_header_parse(const struct sk_buff *skb, const struct net_device *dev,
|
||||
unsigned char *haddr)
|
||||
{
|
||||
const struct ethhdr *eth = eth_hdr(skb);
|
||||
|
||||
memcpy(haddr, eth->h_source, ETH_ALEN);
|
||||
return ETH_ALEN;
|
||||
}
|
||||
|
||||
@@ -1079,10 +1079,12 @@ out:
|
||||
|
||||
static bool icmp_tag_validation(int proto)
|
||||
{
|
||||
const struct net_protocol *ipprot;
|
||||
bool ok;
|
||||
|
||||
rcu_read_lock();
|
||||
ok = rcu_dereference(inet_protos[proto])->icmp_strict_tag_validation;
|
||||
ipprot = rcu_dereference(inet_protos[proto]);
|
||||
ok = ipprot ? ipprot->icmp_strict_tag_validation : false;
|
||||
rcu_read_unlock();
|
||||
return ok;
|
||||
}
|
||||
|
||||
@@ -919,7 +919,8 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
|
||||
return -(t->hlen + sizeof(*iph));
|
||||
}
|
||||
|
||||
static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr)
|
||||
static int ipgre_header_parse(const struct sk_buff *skb, const struct net_device *dev,
|
||||
unsigned char *haddr)
|
||||
{
|
||||
const struct iphdr *iph = (const struct iphdr *) skb_mac_header(skb);
|
||||
memcpy(haddr, &iph->saddr, 4);
|
||||
|
||||
@@ -379,6 +379,10 @@ static int ipv6_srh_rcv(struct sk_buff *skb)
|
||||
hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);
|
||||
|
||||
idev = __in6_dev_get(skb->dev);
|
||||
if (!idev) {
|
||||
kfree_skb(skb);
|
||||
return -1;
|
||||
}
|
||||
|
||||
accept_seg6 = min(READ_ONCE(net->ipv6.devconf_all->seg6_enabled),
|
||||
READ_ONCE(idev->cnf.seg6_enabled));
|
||||
|
||||
@@ -184,6 +184,8 @@ bool seg6_hmac_validate_skb(struct sk_buff *skb)
|
||||
int require_hmac;
|
||||
|
||||
idev = __in6_dev_get(skb->dev);
|
||||
if (!idev)
|
||||
return false;
|
||||
|
||||
srh = (struct ipv6_sr_hdr *)skb_transport_header(skb);
|
||||
|
||||
|
||||
@@ -1904,12 +1904,6 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev,
|
||||
|
||||
__sta_info_flush(sdata, true, link_id, NULL);
|
||||
|
||||
ieee80211_remove_link_keys(link, &keys);
|
||||
if (!list_empty(&keys)) {
|
||||
synchronize_net();
|
||||
ieee80211_free_key_list(local, &keys);
|
||||
}
|
||||
|
||||
ieee80211_stop_mbssid(sdata);
|
||||
RCU_INIT_POINTER(link_conf->tx_bss_conf, NULL);
|
||||
|
||||
@@ -1921,6 +1915,12 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev,
|
||||
ieee80211_link_info_change_notify(sdata, link,
|
||||
BSS_CHANGED_BEACON_ENABLED);
|
||||
|
||||
ieee80211_remove_link_keys(link, &keys);
|
||||
if (!list_empty(&keys)) {
|
||||
synchronize_net();
|
||||
ieee80211_free_key_list(local, &keys);
|
||||
}
|
||||
|
||||
if (sdata->wdev.links[link_id].cac_started) {
|
||||
chandef = link_conf->chanreq.oper;
|
||||
wiphy_hrtimer_work_cancel(wiphy, &link->dfs_cac_timer_work);
|
||||
|
||||
@@ -561,14 +561,16 @@ static void ieee80211_chan_bw_change(struct ieee80211_local *local,
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(sta, &local->sta_list,
|
||||
list) {
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
enum ieee80211_sta_rx_bandwidth new_sta_bw;
|
||||
unsigned int link_id;
|
||||
|
||||
if (!ieee80211_sdata_running(sta->sdata))
|
||||
continue;
|
||||
|
||||
for (link_id = 0; link_id < ARRAY_SIZE(sta->sdata->link); link_id++) {
|
||||
sdata = get_bss_sdata(sta->sdata);
|
||||
|
||||
for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
|
||||
struct ieee80211_link_data *link =
|
||||
rcu_dereference(sdata->link[link_id]);
|
||||
struct ieee80211_bss_conf *link_conf;
|
||||
|
||||
@@ -320,7 +320,6 @@ static ssize_t aql_enable_read(struct file *file, char __user *user_buf,
|
||||
static ssize_t aql_enable_write(struct file *file, const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
bool aql_disabled = static_key_false(&aql_disable.key);
|
||||
char buf[3];
|
||||
size_t len;
|
||||
|
||||
@@ -335,15 +334,12 @@ static ssize_t aql_enable_write(struct file *file, const char __user *user_buf,
|
||||
if (len > 0 && buf[len - 1] == '\n')
|
||||
buf[len - 1] = 0;
|
||||
|
||||
if (buf[0] == '0' && buf[1] == '\0') {
|
||||
if (!aql_disabled)
|
||||
static_branch_inc(&aql_disable);
|
||||
} else if (buf[0] == '1' && buf[1] == '\0') {
|
||||
if (aql_disabled)
|
||||
static_branch_dec(&aql_disable);
|
||||
} else {
|
||||
if (buf[0] == '0' && buf[1] == '\0')
|
||||
static_branch_enable(&aql_disable);
|
||||
else if (buf[0] == '1' && buf[1] == '\0')
|
||||
static_branch_disable(&aql_disable);
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -79,6 +79,9 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
|
||||
* - MDA enabled
|
||||
* - Power management control on fc
|
||||
*/
|
||||
if (!ie->mesh_config)
|
||||
return false;
|
||||
|
||||
if (!(ifmsh->mesh_id_len == ie->mesh_id_len &&
|
||||
memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
|
||||
(ifmsh->mesh_pp_id == ie->mesh_config->meshconf_psel) &&
|
||||
|
||||
@@ -2782,7 +2782,9 @@ static void sta_set_link_sinfo(struct sta_info *sta,
|
||||
}
|
||||
|
||||
link_sinfo->inactive_time =
|
||||
jiffies_to_msecs(jiffies - ieee80211_sta_last_active(sta, link_id));
|
||||
jiffies_delta_to_msecs(jiffies -
|
||||
ieee80211_sta_last_active(sta,
|
||||
link_id));
|
||||
|
||||
if (!(link_sinfo->filled & (BIT_ULL(NL80211_STA_INFO_TX_BYTES64) |
|
||||
BIT_ULL(NL80211_STA_INFO_TX_BYTES)))) {
|
||||
@@ -3015,7 +3017,8 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
|
||||
sinfo->connected_time = ktime_get_seconds() - sta->last_connected;
|
||||
sinfo->assoc_at = sta->assoc_at;
|
||||
sinfo->inactive_time =
|
||||
jiffies_to_msecs(jiffies - ieee80211_sta_last_active(sta, -1));
|
||||
jiffies_delta_to_msecs(jiffies -
|
||||
ieee80211_sta_last_active(sta, -1));
|
||||
|
||||
if (!(sinfo->filled & (BIT_ULL(NL80211_STA_INFO_TX_BYTES64) |
|
||||
BIT_ULL(NL80211_STA_INFO_TX_BYTES)))) {
|
||||
|
||||
@@ -1449,7 +1449,7 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
|
||||
}
|
||||
|
||||
sta = sta_info_get(sdata, peer);
|
||||
if (!sta)
|
||||
if (!sta || !sta->sta.tdls)
|
||||
return -ENOLINK;
|
||||
|
||||
iee80211_tdls_recalc_chanctx(sdata, sta);
|
||||
|
||||
@@ -1899,8 +1899,10 @@ bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
|
||||
struct ieee80211_tx_data tx;
|
||||
struct sk_buff *skb2;
|
||||
|
||||
if (ieee80211_tx_prepare(sdata, &tx, NULL, skb) == TX_DROP)
|
||||
if (ieee80211_tx_prepare(sdata, &tx, NULL, skb) == TX_DROP) {
|
||||
kfree_skb(skb);
|
||||
return false;
|
||||
}
|
||||
|
||||
info->band = band;
|
||||
info->control.vif = vif;
|
||||
|
||||
@@ -469,7 +469,9 @@ static int mac802154_header_create(struct sk_buff *skb,
|
||||
}
|
||||
|
||||
static int
|
||||
mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr)
|
||||
mac802154_header_parse(const struct sk_buff *skb,
|
||||
const struct net_device *dev,
|
||||
unsigned char *haddr)
|
||||
{
|
||||
struct ieee802154_hdr hdr;
|
||||
|
||||
|
||||
@@ -2854,6 +2854,7 @@ out_unregister_rtnl_af:
|
||||
rtnl_af_unregister(&mpls_af_ops);
|
||||
out_unregister_dev_type:
|
||||
dev_remove_pack(&mpls_packet_type);
|
||||
unregister_netdevice_notifier(&mpls_dev_notifier);
|
||||
out_unregister_pernet:
|
||||
unregister_pernet_subsys(&mpls_net_ops);
|
||||
goto out;
|
||||
|
||||
@@ -838,7 +838,7 @@ static struct lock_class_key mptcp_keys[2];
|
||||
static int mptcp_pm_nl_create_listen_socket(struct sock *sk,
|
||||
struct mptcp_pm_addr_entry *entry)
|
||||
{
|
||||
bool is_ipv6 = sk->sk_family == AF_INET6;
|
||||
bool is_ipv6 = entry->addr.family == AF_INET6;
|
||||
int addrlen = sizeof(struct sockaddr_in);
|
||||
struct sockaddr_storage addr;
|
||||
struct sock *newsk, *ssk;
|
||||
|
||||
@@ -170,7 +170,7 @@ static int bpf_nf_link_update(struct bpf_link *link, struct bpf_prog *new_prog,
|
||||
|
||||
static const struct bpf_link_ops bpf_nf_link_lops = {
|
||||
.release = bpf_nf_link_release,
|
||||
.dealloc = bpf_nf_link_dealloc,
|
||||
.dealloc_deferred = bpf_nf_link_dealloc,
|
||||
.detach = bpf_nf_link_detach,
|
||||
.show_fdinfo = bpf_nf_link_show_info,
|
||||
.fill_link_info = bpf_nf_link_fill_link_info,
|
||||
|
||||
@@ -331,6 +331,8 @@ static int decode_int(struct bitstr *bs, const struct field_t *f,
|
||||
if (nf_h323_error_boundary(bs, 0, 2))
|
||||
return H323_ERROR_BOUND;
|
||||
len = get_bits(bs, 2) + 1;
|
||||
if (nf_h323_error_boundary(bs, len, 0))
|
||||
return H323_ERROR_BOUND;
|
||||
BYTE_ALIGN(bs);
|
||||
if (base && (f->attr & DECODE)) { /* timeToLive */
|
||||
unsigned int v = get_uint(bs, len) + f->lb;
|
||||
@@ -922,6 +924,8 @@ int DecodeQ931(unsigned char *buf, size_t sz, Q931 *q931)
|
||||
break;
|
||||
p++;
|
||||
len--;
|
||||
if (len <= 0)
|
||||
break;
|
||||
return DecodeH323_UserInformation(buf, p, len,
|
||||
&q931->UUIE);
|
||||
}
|
||||
|
||||
@@ -3212,7 +3212,7 @@ ctnetlink_exp_ct_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
|
||||
struct nf_conn *ct = cb->data;
|
||||
struct nf_conn_help *help = nfct_help(ct);
|
||||
struct nf_conn_help *help;
|
||||
u_int8_t l3proto = nfmsg->nfgen_family;
|
||||
unsigned long last_id = cb->args[1];
|
||||
struct nf_conntrack_expect *exp;
|
||||
@@ -3220,6 +3220,10 @@ ctnetlink_exp_ct_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
if (cb->args[0])
|
||||
return 0;
|
||||
|
||||
help = nfct_help(ct);
|
||||
if (!help)
|
||||
return 0;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
restart:
|
||||
@@ -3249,6 +3253,24 @@ out:
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
static int ctnetlink_dump_exp_ct_start(struct netlink_callback *cb)
|
||||
{
|
||||
struct nf_conn *ct = cb->data;
|
||||
|
||||
if (!refcount_inc_not_zero(&ct->ct_general.use))
|
||||
return -ENOENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ctnetlink_dump_exp_ct_done(struct netlink_callback *cb)
|
||||
{
|
||||
struct nf_conn *ct = cb->data;
|
||||
|
||||
if (ct)
|
||||
nf_ct_put(ct);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ctnetlink_dump_exp_ct(struct net *net, struct sock *ctnl,
|
||||
struct sk_buff *skb,
|
||||
const struct nlmsghdr *nlh,
|
||||
@@ -3264,6 +3286,8 @@ static int ctnetlink_dump_exp_ct(struct net *net, struct sock *ctnl,
|
||||
struct nf_conntrack_zone zone;
|
||||
struct netlink_dump_control c = {
|
||||
.dump = ctnetlink_exp_ct_dump_table,
|
||||
.start = ctnetlink_dump_exp_ct_start,
|
||||
.done = ctnetlink_dump_exp_ct_done,
|
||||
};
|
||||
|
||||
err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER,
|
||||
@@ -3465,7 +3489,7 @@ ctnetlink_change_expect(struct nf_conntrack_expect *x,
|
||||
|
||||
#if IS_ENABLED(CONFIG_NF_NAT)
|
||||
static const struct nla_policy exp_nat_nla_policy[CTA_EXPECT_NAT_MAX+1] = {
|
||||
[CTA_EXPECT_NAT_DIR] = { .type = NLA_U32 },
|
||||
[CTA_EXPECT_NAT_DIR] = NLA_POLICY_MAX(NLA_BE32, IP_CT_DIR_REPLY),
|
||||
[CTA_EXPECT_NAT_TUPLE] = { .type = NLA_NESTED },
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -582,7 +582,8 @@ nla_put_failure:
|
||||
}
|
||||
|
||||
static const struct nla_policy sctp_nla_policy[CTA_PROTOINFO_SCTP_MAX+1] = {
|
||||
[CTA_PROTOINFO_SCTP_STATE] = { .type = NLA_U8 },
|
||||
[CTA_PROTOINFO_SCTP_STATE] = NLA_POLICY_MAX(NLA_U8,
|
||||
SCTP_CONNTRACK_HEARTBEAT_SENT),
|
||||
[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL] = { .type = NLA_U32 },
|
||||
[CTA_PROTOINFO_SCTP_VTAG_REPLY] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
@@ -1534,11 +1534,12 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,
|
||||
{
|
||||
struct tcphdr *th, _tcph;
|
||||
unsigned int dataoff, datalen;
|
||||
unsigned int matchoff, matchlen, clen;
|
||||
unsigned int matchoff, matchlen;
|
||||
unsigned int msglen, origlen;
|
||||
const char *dptr, *end;
|
||||
s16 diff, tdiff = 0;
|
||||
int ret = NF_ACCEPT;
|
||||
unsigned long clen;
|
||||
bool term;
|
||||
|
||||
if (ctinfo != IP_CT_ESTABLISHED &&
|
||||
@@ -1573,6 +1574,9 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,
|
||||
if (dptr + matchoff == end)
|
||||
break;
|
||||
|
||||
if (clen > datalen)
|
||||
break;
|
||||
|
||||
term = false;
|
||||
for (; end + strlen("\r\n\r\n") <= dptr + datalen; end++) {
|
||||
if (end[0] == '\r' && end[1] == '\n' &&
|
||||
|
||||
@@ -738,6 +738,7 @@ static int nf_flow_encap_push(struct sk_buff *skb,
|
||||
switch (tuple->encap[i].proto) {
|
||||
case htons(ETH_P_8021Q):
|
||||
case htons(ETH_P_8021AD):
|
||||
skb_reset_mac_header(skb);
|
||||
if (skb_vlan_push(skb, tuple->encap[i].proto,
|
||||
tuple->encap[i].id) < 0)
|
||||
return -1;
|
||||
|
||||
@@ -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,
|
||||
struct nft_set_elem_expr *elem_expr)
|
||||
void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
|
||||
struct nft_set_elem_expr *elem_expr)
|
||||
{
|
||||
struct nft_expr *expr;
|
||||
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,
|
||||
const struct nlattr *attr, u32 nlmsg_flags,
|
||||
bool last)
|
||||
const struct nlattr *attr, u32 nlmsg_flags)
|
||||
{
|
||||
struct nft_expr *expr_array[NFT_SET_EXPR_MAX] = {};
|
||||
struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
|
||||
@@ -7444,11 +7443,6 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
|
||||
if (flags)
|
||||
*nft_set_ext_flags(ext) = flags;
|
||||
|
||||
if (last)
|
||||
elem.flags = NFT_SET_ELEM_INTERNAL_LAST;
|
||||
else
|
||||
elem.flags = 0;
|
||||
|
||||
if (obj)
|
||||
*nft_set_ext_obj(ext) = obj;
|
||||
|
||||
@@ -7613,8 +7607,7 @@ static int nf_tables_newsetelem(struct sk_buff *skb,
|
||||
nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
|
||||
|
||||
nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
|
||||
err = nft_add_set_elem(&ctx, set, attr, info->nlh->nlmsg_flags,
|
||||
nla_is_last(attr, rem));
|
||||
err = nft_add_set_elem(&ctx, set, attr, info->nlh->nlmsg_flags);
|
||||
if (err < 0) {
|
||||
NL_SET_BAD_ATTR(extack, attr);
|
||||
return err;
|
||||
@@ -7738,7 +7731,7 @@ static void nft_trans_elems_destroy_abort(const struct nft_ctx *ctx,
|
||||
}
|
||||
|
||||
static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
|
||||
const struct nlattr *attr, bool last)
|
||||
const struct nlattr *attr)
|
||||
{
|
||||
struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
|
||||
struct nft_set_ext_tmpl tmpl;
|
||||
@@ -7806,11 +7799,6 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
|
||||
if (flags)
|
||||
*nft_set_ext_flags(ext) = flags;
|
||||
|
||||
if (last)
|
||||
elem.flags = NFT_SET_ELEM_INTERNAL_LAST;
|
||||
else
|
||||
elem.flags = 0;
|
||||
|
||||
trans = nft_trans_elem_alloc(ctx, NFT_MSG_DELSETELEM, set);
|
||||
if (trans == NULL)
|
||||
goto fail_trans;
|
||||
@@ -7961,8 +7949,7 @@ static int nf_tables_delsetelem(struct sk_buff *skb,
|
||||
return nft_set_flush(&ctx, set, genmask);
|
||||
|
||||
nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
|
||||
err = nft_del_setelem(&ctx, set, attr,
|
||||
nla_is_last(attr, rem));
|
||||
err = nft_del_setelem(&ctx, set, attr);
|
||||
if (err == -ENOENT &&
|
||||
NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYSETELEM)
|
||||
continue;
|
||||
@@ -9216,6 +9203,7 @@ static int nf_tables_newflowtable(struct sk_buff *skb,
|
||||
return 0;
|
||||
|
||||
err_flowtable_hooks:
|
||||
synchronize_rcu();
|
||||
nft_trans_destroy(trans);
|
||||
err_flowtable_trans:
|
||||
nft_hooks_destroy(&flowtable->hook_list);
|
||||
|
||||
@@ -302,7 +302,9 @@ static int nfnl_osf_add_callback(struct sk_buff *skb,
|
||||
{
|
||||
struct nf_osf_user_finger *f;
|
||||
struct nf_osf_finger *kf = NULL, *sf;
|
||||
unsigned int tot_opt_len = 0;
|
||||
int err = 0;
|
||||
int i;
|
||||
|
||||
if (!capable(CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
@@ -318,6 +320,17 @@ static int nfnl_osf_add_callback(struct sk_buff *skb,
|
||||
if (f->opt_num > ARRAY_SIZE(f->opt))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < f->opt_num; i++) {
|
||||
if (!f->opt[i].length || f->opt[i].length > MAX_IPOPTLEN)
|
||||
return -EINVAL;
|
||||
if (f->opt[i].kind == OSFOPT_MSS && f->opt[i].length < 4)
|
||||
return -EINVAL;
|
||||
|
||||
tot_opt_len += f->opt[i].length;
|
||||
if (tot_opt_len > MAX_IPOPTLEN)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!memchr(f->genre, 0, MAXGENRELEN) ||
|
||||
!memchr(f->subtype, 0, MAXGENRELEN) ||
|
||||
!memchr(f->version, 0, MAXGENRELEN))
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <net/netfilter/nf_conntrack_l4proto.h>
|
||||
#include <net/netfilter/nf_conntrack_expect.h>
|
||||
#include <net/netfilter/nf_conntrack_seqadj.h>
|
||||
#include "nf_internals.h"
|
||||
|
||||
struct nft_ct_helper_obj {
|
||||
struct nf_conntrack_helper *helper4;
|
||||
@@ -543,6 +544,7 @@ static void __nft_ct_set_destroy(const struct nft_ctx *ctx, struct nft_ct *priv)
|
||||
#endif
|
||||
#ifdef CONFIG_NF_CONNTRACK_ZONES
|
||||
case NFT_CT_ZONE:
|
||||
nf_queue_nf_hook_drop(ctx->net);
|
||||
mutex_lock(&nft_ct_pcpu_mutex);
|
||||
if (--nft_ct_pcpu_template_refcnt == 0)
|
||||
nft_ct_tmpl_put_pcpu();
|
||||
@@ -1015,6 +1017,7 @@ static void nft_ct_timeout_obj_destroy(const struct nft_ctx *ctx,
|
||||
struct nft_ct_timeout_obj *priv = nft_obj_data(obj);
|
||||
struct nf_ct_timeout *timeout = priv->timeout;
|
||||
|
||||
nf_queue_nf_hook_drop(ctx->net);
|
||||
nf_ct_untimeout(ctx->net, timeout);
|
||||
nf_ct_netns_put(ctx->net, ctx->family);
|
||||
kfree(priv->timeout);
|
||||
@@ -1147,6 +1150,7 @@ static void nft_ct_helper_obj_destroy(const struct nft_ctx *ctx,
|
||||
{
|
||||
struct nft_ct_helper_obj *priv = nft_obj_data(obj);
|
||||
|
||||
nf_queue_nf_hook_drop(ctx->net);
|
||||
if (priv->helper4)
|
||||
nf_conntrack_helper_put(priv->helper4);
|
||||
if (priv->helper6)
|
||||
|
||||
@@ -30,18 +30,26 @@ static int nft_dynset_expr_setup(const struct nft_dynset *priv,
|
||||
const struct nft_set_ext *ext)
|
||||
{
|
||||
struct nft_set_elem_expr *elem_expr = nft_set_ext_expr(ext);
|
||||
struct nft_ctx ctx = {
|
||||
.net = read_pnet(&priv->set->net),
|
||||
.family = priv->set->table->family,
|
||||
};
|
||||
struct nft_expr *expr;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < priv->num_exprs; i++) {
|
||||
expr = nft_setelem_expr_at(elem_expr, elem_expr->size);
|
||||
if (nft_expr_clone(expr, priv->expr_array[i], GFP_ATOMIC) < 0)
|
||||
return -1;
|
||||
goto err_out;
|
||||
|
||||
elem_expr->size += priv->expr_array[i]->ops->size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_out:
|
||||
nft_set_elem_expr_destroy(&ctx, elem_expr);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct nft_elem_priv *nft_dynset_new(struct nft_set *set,
|
||||
|
||||
@@ -304,19 +304,10 @@ static void nft_rbtree_set_start_cookie(struct nft_rbtree *priv,
|
||||
priv->start_rbe_cookie = (unsigned long)rbe;
|
||||
}
|
||||
|
||||
static void nft_rbtree_set_start_cookie_open(struct nft_rbtree *priv,
|
||||
const struct nft_rbtree_elem *rbe,
|
||||
unsigned long open_interval)
|
||||
{
|
||||
priv->start_rbe_cookie = (unsigned long)rbe | open_interval;
|
||||
}
|
||||
|
||||
#define NFT_RBTREE_OPEN_INTERVAL 1UL
|
||||
|
||||
static bool nft_rbtree_cmp_start_cookie(struct nft_rbtree *priv,
|
||||
const struct nft_rbtree_elem *rbe)
|
||||
{
|
||||
return (priv->start_rbe_cookie & ~NFT_RBTREE_OPEN_INTERVAL) == (unsigned long)rbe;
|
||||
return priv->start_rbe_cookie == (unsigned long)rbe;
|
||||
}
|
||||
|
||||
static bool nft_rbtree_insert_same_interval(const struct net *net,
|
||||
@@ -346,14 +337,13 @@ static bool nft_rbtree_insert_same_interval(const struct net *net,
|
||||
|
||||
static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
|
||||
struct nft_rbtree_elem *new,
|
||||
struct nft_elem_priv **elem_priv, u64 tstamp, bool last)
|
||||
struct nft_elem_priv **elem_priv, u64 tstamp)
|
||||
{
|
||||
struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL, *rbe_prev;
|
||||
struct rb_node *node, *next, *parent, **p, *first = NULL;
|
||||
struct nft_rbtree *priv = nft_set_priv(set);
|
||||
u8 cur_genmask = nft_genmask_cur(net);
|
||||
u8 genmask = nft_genmask_next(net);
|
||||
unsigned long open_interval = 0;
|
||||
int d;
|
||||
|
||||
/* Descend the tree to search for an existing element greater than the
|
||||
@@ -459,18 +449,10 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
|
||||
}
|
||||
}
|
||||
|
||||
if (nft_rbtree_interval_null(set, new)) {
|
||||
if (nft_rbtree_interval_null(set, new))
|
||||
priv->start_rbe_cookie = 0;
|
||||
else if (nft_rbtree_interval_start(new) && priv->start_rbe_cookie)
|
||||
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
|
||||
* reported as -EEXIST, cleared by caller if NLM_F_EXCL is not given.
|
||||
@@ -478,27 +460,7 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
|
||||
if (rbe_ge && !nft_rbtree_cmp(set, new, rbe_ge) &&
|
||||
nft_rbtree_interval_start(rbe_ge) == nft_rbtree_interval_start(new)) {
|
||||
*elem_priv = &rbe_ge->priv;
|
||||
|
||||
/* - Corner case: new start element of open interval (which
|
||||
* comes as last element in the batch) overlaps the start of
|
||||
* an existing interval with an end element: partial overlap.
|
||||
*/
|
||||
node = rb_first(&priv->root);
|
||||
rbe = __nft_rbtree_next_active(node, genmask);
|
||||
if (rbe && nft_rbtree_interval_end(rbe)) {
|
||||
rbe = nft_rbtree_next_active(rbe, genmask);
|
||||
if (rbe &&
|
||||
nft_rbtree_interval_start(rbe) &&
|
||||
!nft_rbtree_cmp(set, new, rbe)) {
|
||||
if (last)
|
||||
return -ENOTEMPTY;
|
||||
|
||||
/* Maybe open interval? */
|
||||
open_interval = NFT_RBTREE_OPEN_INTERVAL;
|
||||
}
|
||||
}
|
||||
nft_rbtree_set_start_cookie_open(priv, rbe_ge, open_interval);
|
||||
|
||||
nft_rbtree_set_start_cookie(priv, rbe_ge);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
@@ -553,12 +515,6 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
|
||||
nft_rbtree_interval_end(rbe_ge) && nft_rbtree_interval_end(new))
|
||||
return -ENOTEMPTY;
|
||||
|
||||
/* - start element overlaps an open interval but end element is new:
|
||||
* partial overlap, reported as -ENOEMPTY.
|
||||
*/
|
||||
if (!rbe_ge && priv->start_rbe_cookie && nft_rbtree_interval_end(new))
|
||||
return -ENOTEMPTY;
|
||||
|
||||
/* Accepted element: pick insertion point depending on key value */
|
||||
parent = NULL;
|
||||
p = &priv->root.rb_node;
|
||||
@@ -668,7 +624,6 @@ static int nft_rbtree_insert(const struct net *net, const struct nft_set *set,
|
||||
struct nft_elem_priv **elem_priv)
|
||||
{
|
||||
struct nft_rbtree_elem *rbe = nft_elem_priv_cast(elem->priv);
|
||||
bool last = !!(elem->flags & NFT_SET_ELEM_INTERNAL_LAST);
|
||||
struct nft_rbtree *priv = nft_set_priv(set);
|
||||
u64 tstamp = nft_net_tstamp(net);
|
||||
int err;
|
||||
@@ -685,12 +640,8 @@ static int nft_rbtree_insert(const struct net *net, const struct nft_set *set,
|
||||
cond_resched();
|
||||
|
||||
write_lock_bh(&priv->lock);
|
||||
err = __nft_rbtree_insert(net, set, rbe, elem_priv, tstamp, last);
|
||||
err = __nft_rbtree_insert(net, set, rbe, elem_priv, tstamp);
|
||||
write_unlock_bh(&priv->lock);
|
||||
|
||||
if (nft_rbtree_interval_end(rbe))
|
||||
priv->start_rbe_cookie = 0;
|
||||
|
||||
} while (err == -EAGAIN);
|
||||
|
||||
return err;
|
||||
@@ -778,7 +729,6 @@ nft_rbtree_deactivate(const struct net *net, const struct nft_set *set,
|
||||
const struct nft_set_elem *elem)
|
||||
{
|
||||
struct nft_rbtree_elem *rbe, *this = nft_elem_priv_cast(elem->priv);
|
||||
bool last = !!(elem->flags & NFT_SET_ELEM_INTERNAL_LAST);
|
||||
struct nft_rbtree *priv = nft_set_priv(set);
|
||||
const struct rb_node *parent = priv->root.rb_node;
|
||||
u8 genmask = nft_genmask_next(net);
|
||||
@@ -819,10 +769,9 @@ nft_rbtree_deactivate(const struct net *net, const struct nft_set *set,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nft_rbtree_interval_start(rbe)) {
|
||||
if (!last)
|
||||
nft_rbtree_set_start_cookie(priv, rbe);
|
||||
} else if (!nft_rbtree_deactivate_same_interval(net, priv, rbe))
|
||||
if (nft_rbtree_interval_start(rbe))
|
||||
nft_rbtree_set_start_cookie(priv, rbe);
|
||||
else if (!nft_rbtree_deactivate_same_interval(net, priv, rbe))
|
||||
return NULL;
|
||||
|
||||
nft_rbtree_flush(net, set, &rbe->priv);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <net/netfilter/nf_conntrack_ecache.h>
|
||||
#include <net/netfilter/nf_conntrack_timeout.h>
|
||||
#include <net/netfilter/nf_conntrack_zones.h>
|
||||
#include "nf_internals.h"
|
||||
|
||||
static inline int xt_ct_target(struct sk_buff *skb, struct nf_conn *ct)
|
||||
{
|
||||
@@ -283,6 +284,9 @@ static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par,
|
||||
struct nf_conn_help *help;
|
||||
|
||||
if (ct) {
|
||||
if (info->helper[0] || info->timeout[0])
|
||||
nf_queue_nf_hook_drop(par->net);
|
||||
|
||||
help = nfct_help(ct);
|
||||
xt_ct_put_helper(help);
|
||||
|
||||
|
||||
@@ -223,13 +223,13 @@ time_mt(const struct sk_buff *skb, struct xt_action_param *par)
|
||||
|
||||
localtime_2(¤t_time, stamp);
|
||||
|
||||
if (!(info->weekdays_match & (1 << current_time.weekday)))
|
||||
if (!(info->weekdays_match & (1U << current_time.weekday)))
|
||||
return false;
|
||||
|
||||
/* Do not spend time computing monthday if all days match anyway */
|
||||
if (info->monthdays_match != XT_TIME_ALL_MONTHDAYS) {
|
||||
localtime_3(¤t_time, stamp);
|
||||
if (!(info->monthdays_match & (1 << current_time.monthday)))
|
||||
if (!(info->monthdays_match & (1U << current_time.monthday)))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -129,9 +129,12 @@ static int pn_header_create(struct sk_buff *skb, struct net_device *dev,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int pn_header_parse(const struct sk_buff *skb, unsigned char *haddr)
|
||||
static int pn_header_parse(const struct sk_buff *skb,
|
||||
const struct net_device *dev,
|
||||
unsigned char *haddr)
|
||||
{
|
||||
const u8 *media = skb_mac_header(skb);
|
||||
|
||||
*haddr = *media;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -811,6 +811,11 @@ static int rose_connect(struct socket *sock, struct sockaddr_unsized *uaddr, int
|
||||
goto out_release;
|
||||
}
|
||||
|
||||
if (sk->sk_state == TCP_SYN_SENT) {
|
||||
err = -EALREADY;
|
||||
goto out_release;
|
||||
}
|
||||
|
||||
sk->sk_state = TCP_CLOSE;
|
||||
sock->state = SS_UNCONNECTED;
|
||||
|
||||
|
||||
@@ -1288,33 +1288,6 @@ static void dev_deactivate_queue(struct net_device *dev,
|
||||
}
|
||||
}
|
||||
|
||||
static void dev_reset_queue(struct net_device *dev,
|
||||
struct netdev_queue *dev_queue,
|
||||
void *_unused)
|
||||
{
|
||||
struct Qdisc *qdisc;
|
||||
bool nolock;
|
||||
|
||||
qdisc = rtnl_dereference(dev_queue->qdisc_sleeping);
|
||||
if (!qdisc)
|
||||
return;
|
||||
|
||||
nolock = qdisc->flags & TCQ_F_NOLOCK;
|
||||
|
||||
if (nolock)
|
||||
spin_lock_bh(&qdisc->seqlock);
|
||||
spin_lock_bh(qdisc_lock(qdisc));
|
||||
|
||||
qdisc_reset(qdisc);
|
||||
|
||||
spin_unlock_bh(qdisc_lock(qdisc));
|
||||
if (nolock) {
|
||||
clear_bit(__QDISC_STATE_MISSED, &qdisc->state);
|
||||
clear_bit(__QDISC_STATE_DRAINING, &qdisc->state);
|
||||
spin_unlock_bh(&qdisc->seqlock);
|
||||
}
|
||||
}
|
||||
|
||||
static bool some_qdisc_is_busy(struct net_device *dev)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
@@ -113,14 +113,15 @@ static void ingress_destroy(struct Qdisc *sch)
|
||||
{
|
||||
struct ingress_sched_data *q = qdisc_priv(sch);
|
||||
struct net_device *dev = qdisc_dev(sch);
|
||||
struct bpf_mprog_entry *entry = rtnl_dereference(dev->tcx_ingress);
|
||||
struct bpf_mprog_entry *entry;
|
||||
|
||||
if (sch->parent != TC_H_INGRESS)
|
||||
return;
|
||||
|
||||
tcf_block_put_ext(q->block, sch, &q->block_info);
|
||||
|
||||
if (entry) {
|
||||
if (mini_qdisc_pair_inited(&q->miniqp)) {
|
||||
entry = rtnl_dereference(dev->tcx_ingress);
|
||||
tcx_miniq_dec(entry);
|
||||
if (!tcx_entry_is_active(entry)) {
|
||||
tcx_entry_update(dev, NULL, true);
|
||||
@@ -290,10 +291,9 @@ static int clsact_init(struct Qdisc *sch, struct nlattr *opt,
|
||||
|
||||
static void clsact_destroy(struct Qdisc *sch)
|
||||
{
|
||||
struct bpf_mprog_entry *ingress_entry, *egress_entry;
|
||||
struct clsact_sched_data *q = qdisc_priv(sch);
|
||||
struct net_device *dev = qdisc_dev(sch);
|
||||
struct bpf_mprog_entry *ingress_entry = rtnl_dereference(dev->tcx_ingress);
|
||||
struct bpf_mprog_entry *egress_entry = rtnl_dereference(dev->tcx_egress);
|
||||
|
||||
if (sch->parent != TC_H_CLSACT)
|
||||
return;
|
||||
@@ -301,7 +301,8 @@ static void clsact_destroy(struct Qdisc *sch)
|
||||
tcf_block_put_ext(q->ingress_block, sch, &q->ingress_block_info);
|
||||
tcf_block_put_ext(q->egress_block, sch, &q->egress_block_info);
|
||||
|
||||
if (ingress_entry) {
|
||||
if (mini_qdisc_pair_inited(&q->miniqp_ingress)) {
|
||||
ingress_entry = rtnl_dereference(dev->tcx_ingress);
|
||||
tcx_miniq_dec(ingress_entry);
|
||||
if (!tcx_entry_is_active(ingress_entry)) {
|
||||
tcx_entry_update(dev, NULL, true);
|
||||
@@ -309,7 +310,8 @@ static void clsact_destroy(struct Qdisc *sch)
|
||||
}
|
||||
}
|
||||
|
||||
if (egress_entry) {
|
||||
if (mini_qdisc_pair_inited(&q->miniqp_egress)) {
|
||||
egress_entry = rtnl_dereference(dev->tcx_egress);
|
||||
tcx_miniq_dec(egress_entry);
|
||||
if (!tcx_entry_is_active(egress_entry)) {
|
||||
tcx_entry_update(dev, NULL, false);
|
||||
|
||||
@@ -146,15 +146,12 @@ teql_destroy(struct Qdisc *sch)
|
||||
master->slaves = NEXT_SLAVE(q);
|
||||
if (q == master->slaves) {
|
||||
struct netdev_queue *txq;
|
||||
spinlock_t *root_lock;
|
||||
|
||||
txq = netdev_get_tx_queue(master->dev, 0);
|
||||
master->slaves = NULL;
|
||||
|
||||
root_lock = qdisc_root_sleeping_lock(rtnl_dereference(txq->qdisc));
|
||||
spin_lock_bh(root_lock);
|
||||
qdisc_reset(rtnl_dereference(txq->qdisc));
|
||||
spin_unlock_bh(root_lock);
|
||||
dev_reset_queue(master->dev,
|
||||
txq, NULL);
|
||||
}
|
||||
}
|
||||
skb_queue_purge(&dat->q);
|
||||
|
||||
@@ -36,24 +36,6 @@ static struct net_shaper_binding *net_shaper_binding_from_ctx(void *ctx)
|
||||
return &((struct net_shaper_nl_ctx *)ctx)->binding;
|
||||
}
|
||||
|
||||
static void net_shaper_lock(struct net_shaper_binding *binding)
|
||||
{
|
||||
switch (binding->type) {
|
||||
case NET_SHAPER_BINDING_TYPE_NETDEV:
|
||||
netdev_lock(binding->netdev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void net_shaper_unlock(struct net_shaper_binding *binding)
|
||||
{
|
||||
switch (binding->type) {
|
||||
case NET_SHAPER_BINDING_TYPE_NETDEV:
|
||||
netdev_unlock(binding->netdev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct net_shaper_hierarchy *
|
||||
net_shaper_hierarchy(struct net_shaper_binding *binding)
|
||||
{
|
||||
@@ -65,6 +47,21 @@ net_shaper_hierarchy(struct net_shaper_binding *binding)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct net_shaper_hierarchy *
|
||||
net_shaper_hierarchy_rcu(struct net_shaper_binding *binding)
|
||||
{
|
||||
/* Readers look up the device and take a ref, then take RCU lock
|
||||
* later at which point netdev may have been unregistered and flushed.
|
||||
* READ_ONCE() pairs with WRITE_ONCE() in net_shaper_hierarchy_setup.
|
||||
*/
|
||||
if (binding->type == NET_SHAPER_BINDING_TYPE_NETDEV &&
|
||||
READ_ONCE(binding->netdev->reg_state) <= NETREG_REGISTERED)
|
||||
return READ_ONCE(binding->netdev->net_shaper_hierarchy);
|
||||
|
||||
/* No other type supported yet. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const struct net_shaper_ops *
|
||||
net_shaper_ops(struct net_shaper_binding *binding)
|
||||
{
|
||||
@@ -204,12 +201,49 @@ static int net_shaper_ctx_setup(const struct genl_info *info, int type,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Like net_shaper_ctx_setup(), but for "write" handlers (never for dumps!)
|
||||
* Acquires the lock protecting the hierarchy (instance lock for netdev).
|
||||
*/
|
||||
static int net_shaper_ctx_setup_lock(const struct genl_info *info, int type,
|
||||
struct net_shaper_nl_ctx *ctx)
|
||||
{
|
||||
struct net *ns = genl_info_net(info);
|
||||
struct net_device *dev;
|
||||
int ifindex;
|
||||
|
||||
if (GENL_REQ_ATTR_CHECK(info, type))
|
||||
return -EINVAL;
|
||||
|
||||
ifindex = nla_get_u32(info->attrs[type]);
|
||||
dev = netdev_get_by_index_lock(ns, ifindex);
|
||||
if (!dev) {
|
||||
NL_SET_BAD_ATTR(info->extack, info->attrs[type]);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!dev->netdev_ops->net_shaper_ops) {
|
||||
NL_SET_BAD_ATTR(info->extack, info->attrs[type]);
|
||||
netdev_unlock(dev);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
ctx->binding.type = NET_SHAPER_BINDING_TYPE_NETDEV;
|
||||
ctx->binding.netdev = dev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void net_shaper_ctx_cleanup(struct net_shaper_nl_ctx *ctx)
|
||||
{
|
||||
if (ctx->binding.type == NET_SHAPER_BINDING_TYPE_NETDEV)
|
||||
netdev_put(ctx->binding.netdev, &ctx->dev_tracker);
|
||||
}
|
||||
|
||||
static void net_shaper_ctx_cleanup_unlock(struct net_shaper_nl_ctx *ctx)
|
||||
{
|
||||
if (ctx->binding.type == NET_SHAPER_BINDING_TYPE_NETDEV)
|
||||
netdev_unlock(ctx->binding.netdev);
|
||||
}
|
||||
|
||||
static u32 net_shaper_handle_to_index(const struct net_shaper_handle *handle)
|
||||
{
|
||||
return FIELD_PREP(NET_SHAPER_SCOPE_MASK, handle->scope) |
|
||||
@@ -251,9 +285,10 @@ static struct net_shaper *
|
||||
net_shaper_lookup(struct net_shaper_binding *binding,
|
||||
const struct net_shaper_handle *handle)
|
||||
{
|
||||
struct net_shaper_hierarchy *hierarchy = net_shaper_hierarchy(binding);
|
||||
u32 index = net_shaper_handle_to_index(handle);
|
||||
struct net_shaper_hierarchy *hierarchy;
|
||||
|
||||
hierarchy = net_shaper_hierarchy_rcu(binding);
|
||||
if (!hierarchy || xa_get_mark(&hierarchy->shapers, index,
|
||||
NET_SHAPER_NOT_VALID))
|
||||
return NULL;
|
||||
@@ -262,7 +297,7 @@ net_shaper_lookup(struct net_shaper_binding *binding,
|
||||
}
|
||||
|
||||
/* Allocate on demand the per device shaper's hierarchy container.
|
||||
* Called under the net shaper lock
|
||||
* Called under the lock protecting the hierarchy (instance lock for netdev)
|
||||
*/
|
||||
static struct net_shaper_hierarchy *
|
||||
net_shaper_hierarchy_setup(struct net_shaper_binding *binding)
|
||||
@@ -681,6 +716,22 @@ void net_shaper_nl_post_doit(const struct genl_split_ops *ops,
|
||||
net_shaper_generic_post(info);
|
||||
}
|
||||
|
||||
int net_shaper_nl_pre_doit_write(const struct genl_split_ops *ops,
|
||||
struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct net_shaper_nl_ctx *ctx = (struct net_shaper_nl_ctx *)info->ctx;
|
||||
|
||||
BUILD_BUG_ON(sizeof(*ctx) > sizeof(info->ctx));
|
||||
|
||||
return net_shaper_ctx_setup_lock(info, NET_SHAPER_A_IFINDEX, ctx);
|
||||
}
|
||||
|
||||
void net_shaper_nl_post_doit_write(const struct genl_split_ops *ops,
|
||||
struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
net_shaper_ctx_cleanup_unlock((struct net_shaper_nl_ctx *)info->ctx);
|
||||
}
|
||||
|
||||
int net_shaper_nl_pre_dumpit(struct netlink_callback *cb)
|
||||
{
|
||||
struct net_shaper_nl_ctx *ctx = (struct net_shaper_nl_ctx *)cb->ctx;
|
||||
@@ -778,17 +829,19 @@ int net_shaper_nl_get_dumpit(struct sk_buff *skb,
|
||||
|
||||
/* Don't error out dumps performed before any set operation. */
|
||||
binding = net_shaper_binding_from_ctx(ctx);
|
||||
hierarchy = net_shaper_hierarchy(binding);
|
||||
if (!hierarchy)
|
||||
return 0;
|
||||
|
||||
rcu_read_lock();
|
||||
hierarchy = net_shaper_hierarchy_rcu(binding);
|
||||
if (!hierarchy)
|
||||
goto out_unlock;
|
||||
|
||||
for (; (shaper = xa_find(&hierarchy->shapers, &ctx->start_index,
|
||||
U32_MAX, XA_PRESENT)); ctx->start_index++) {
|
||||
ret = net_shaper_fill_one(skb, binding, shaper, info);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
out_unlock:
|
||||
rcu_read_unlock();
|
||||
|
||||
return ret;
|
||||
@@ -806,45 +859,38 @@ int net_shaper_nl_set_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
binding = net_shaper_binding_from_ctx(info->ctx);
|
||||
|
||||
net_shaper_lock(binding);
|
||||
ret = net_shaper_parse_info(binding, info->attrs, info, &shaper,
|
||||
&exists);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
return ret;
|
||||
|
||||
if (!exists)
|
||||
net_shaper_default_parent(&shaper.handle, &shaper.parent);
|
||||
|
||||
hierarchy = net_shaper_hierarchy_setup(binding);
|
||||
if (!hierarchy) {
|
||||
ret = -ENOMEM;
|
||||
goto unlock;
|
||||
}
|
||||
if (!hierarchy)
|
||||
return -ENOMEM;
|
||||
|
||||
/* The 'set' operation can't create node-scope shapers. */
|
||||
handle = shaper.handle;
|
||||
if (handle.scope == NET_SHAPER_SCOPE_NODE &&
|
||||
!net_shaper_lookup(binding, &handle)) {
|
||||
ret = -ENOENT;
|
||||
goto unlock;
|
||||
}
|
||||
!net_shaper_lookup(binding, &handle))
|
||||
return -ENOENT;
|
||||
|
||||
ret = net_shaper_pre_insert(binding, &handle, info->extack);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
return ret;
|
||||
|
||||
ops = net_shaper_ops(binding);
|
||||
ret = ops->set(binding, &shaper, info->extack);
|
||||
if (ret) {
|
||||
net_shaper_rollback(binding);
|
||||
goto unlock;
|
||||
return ret;
|
||||
}
|
||||
|
||||
net_shaper_commit(binding, 1, &shaper);
|
||||
|
||||
unlock:
|
||||
net_shaper_unlock(binding);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __net_shaper_delete(struct net_shaper_binding *binding,
|
||||
@@ -1072,35 +1118,26 @@ int net_shaper_nl_delete_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
binding = net_shaper_binding_from_ctx(info->ctx);
|
||||
|
||||
net_shaper_lock(binding);
|
||||
ret = net_shaper_parse_handle(info->attrs[NET_SHAPER_A_HANDLE], info,
|
||||
&handle);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
return ret;
|
||||
|
||||
hierarchy = net_shaper_hierarchy(binding);
|
||||
if (!hierarchy) {
|
||||
ret = -ENOENT;
|
||||
goto unlock;
|
||||
}
|
||||
if (!hierarchy)
|
||||
return -ENOENT;
|
||||
|
||||
shaper = net_shaper_lookup(binding, &handle);
|
||||
if (!shaper) {
|
||||
ret = -ENOENT;
|
||||
goto unlock;
|
||||
}
|
||||
if (!shaper)
|
||||
return -ENOENT;
|
||||
|
||||
if (handle.scope == NET_SHAPER_SCOPE_NODE) {
|
||||
ret = net_shaper_pre_del_node(binding, shaper, info->extack);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = __net_shaper_delete(binding, shaper, info->extack);
|
||||
|
||||
unlock:
|
||||
net_shaper_unlock(binding);
|
||||
return ret;
|
||||
return __net_shaper_delete(binding, shaper, info->extack);
|
||||
}
|
||||
|
||||
static int net_shaper_group_send_reply(struct net_shaper_binding *binding,
|
||||
@@ -1149,21 +1186,17 @@ int net_shaper_nl_group_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
if (!net_shaper_ops(binding)->group)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
net_shaper_lock(binding);
|
||||
leaves_count = net_shaper_list_len(info, NET_SHAPER_A_LEAVES);
|
||||
if (!leaves_count) {
|
||||
NL_SET_BAD_ATTR(info->extack,
|
||||
info->attrs[NET_SHAPER_A_LEAVES]);
|
||||
ret = -EINVAL;
|
||||
goto unlock;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
leaves = kcalloc(leaves_count, sizeof(struct net_shaper) +
|
||||
sizeof(struct net_shaper *), GFP_KERNEL);
|
||||
if (!leaves) {
|
||||
ret = -ENOMEM;
|
||||
goto unlock;
|
||||
}
|
||||
if (!leaves)
|
||||
return -ENOMEM;
|
||||
old_nodes = (void *)&leaves[leaves_count];
|
||||
|
||||
ret = net_shaper_parse_node(binding, info->attrs, info, &node);
|
||||
@@ -1240,9 +1273,6 @@ int net_shaper_nl_group_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
free_leaves:
|
||||
kfree(leaves);
|
||||
|
||||
unlock:
|
||||
net_shaper_unlock(binding);
|
||||
return ret;
|
||||
|
||||
free_msg:
|
||||
@@ -1352,14 +1382,12 @@ static void net_shaper_flush(struct net_shaper_binding *binding)
|
||||
if (!hierarchy)
|
||||
return;
|
||||
|
||||
net_shaper_lock(binding);
|
||||
xa_lock(&hierarchy->shapers);
|
||||
xa_for_each(&hierarchy->shapers, index, cur) {
|
||||
__xa_erase(&hierarchy->shapers, index);
|
||||
kfree(cur);
|
||||
}
|
||||
xa_unlock(&hierarchy->shapers);
|
||||
net_shaper_unlock(binding);
|
||||
|
||||
kfree(hierarchy);
|
||||
}
|
||||
|
||||
@@ -99,27 +99,27 @@ static const struct genl_split_ops net_shaper_nl_ops[] = {
|
||||
},
|
||||
{
|
||||
.cmd = NET_SHAPER_CMD_SET,
|
||||
.pre_doit = net_shaper_nl_pre_doit,
|
||||
.pre_doit = net_shaper_nl_pre_doit_write,
|
||||
.doit = net_shaper_nl_set_doit,
|
||||
.post_doit = net_shaper_nl_post_doit,
|
||||
.post_doit = net_shaper_nl_post_doit_write,
|
||||
.policy = net_shaper_set_nl_policy,
|
||||
.maxattr = NET_SHAPER_A_IFINDEX,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
||||
},
|
||||
{
|
||||
.cmd = NET_SHAPER_CMD_DELETE,
|
||||
.pre_doit = net_shaper_nl_pre_doit,
|
||||
.pre_doit = net_shaper_nl_pre_doit_write,
|
||||
.doit = net_shaper_nl_delete_doit,
|
||||
.post_doit = net_shaper_nl_post_doit,
|
||||
.post_doit = net_shaper_nl_post_doit_write,
|
||||
.policy = net_shaper_delete_nl_policy,
|
||||
.maxattr = NET_SHAPER_A_IFINDEX,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
||||
},
|
||||
{
|
||||
.cmd = NET_SHAPER_CMD_GROUP,
|
||||
.pre_doit = net_shaper_nl_pre_doit,
|
||||
.pre_doit = net_shaper_nl_pre_doit_write,
|
||||
.doit = net_shaper_nl_group_doit,
|
||||
.post_doit = net_shaper_nl_post_doit,
|
||||
.post_doit = net_shaper_nl_post_doit_write,
|
||||
.policy = net_shaper_group_nl_policy,
|
||||
.maxattr = NET_SHAPER_A_LEAVES,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
||||
|
||||
@@ -18,12 +18,17 @@ extern const struct nla_policy net_shaper_leaf_info_nl_policy[NET_SHAPER_A_WEIGH
|
||||
|
||||
int net_shaper_nl_pre_doit(const struct genl_split_ops *ops,
|
||||
struct sk_buff *skb, struct genl_info *info);
|
||||
int net_shaper_nl_pre_doit_write(const struct genl_split_ops *ops,
|
||||
struct sk_buff *skb, struct genl_info *info);
|
||||
int net_shaper_nl_cap_pre_doit(const struct genl_split_ops *ops,
|
||||
struct sk_buff *skb, struct genl_info *info);
|
||||
void
|
||||
net_shaper_nl_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
|
||||
struct genl_info *info);
|
||||
void
|
||||
net_shaper_nl_post_doit_write(const struct genl_split_ops *ops,
|
||||
struct sk_buff *skb, struct genl_info *info);
|
||||
void
|
||||
net_shaper_nl_cap_post_doit(const struct genl_split_ops *ops,
|
||||
struct sk_buff *skb, struct genl_info *info);
|
||||
int net_shaper_nl_pre_dumpit(struct netlink_callback *cb);
|
||||
|
||||
@@ -131,7 +131,14 @@ static struct sock *smc_tcp_syn_recv_sock(const struct sock *sk,
|
||||
struct smc_sock *smc;
|
||||
struct sock *child;
|
||||
|
||||
smc = smc_clcsock_user_data(sk);
|
||||
rcu_read_lock();
|
||||
smc = smc_clcsock_user_data_rcu(sk);
|
||||
if (!smc || !refcount_inc_not_zero(&smc->sk.sk_refcnt)) {
|
||||
rcu_read_unlock();
|
||||
smc = NULL;
|
||||
goto drop;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (READ_ONCE(sk->sk_ack_backlog) + atomic_read(&smc->queued_smc_hs) >
|
||||
sk->sk_max_ack_backlog)
|
||||
@@ -153,11 +160,14 @@ static struct sock *smc_tcp_syn_recv_sock(const struct sock *sk,
|
||||
if (inet_csk(child)->icsk_af_ops == inet_csk(sk)->icsk_af_ops)
|
||||
inet_csk(child)->icsk_af_ops = smc->ori_af_ops;
|
||||
}
|
||||
sock_put(&smc->sk);
|
||||
return child;
|
||||
|
||||
drop:
|
||||
dst_release(dst);
|
||||
tcp_listendrop(sk);
|
||||
if (smc)
|
||||
sock_put(&smc->sk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -254,7 +264,7 @@ static void smc_fback_restore_callbacks(struct smc_sock *smc)
|
||||
struct sock *clcsk = smc->clcsock->sk;
|
||||
|
||||
write_lock_bh(&clcsk->sk_callback_lock);
|
||||
clcsk->sk_user_data = NULL;
|
||||
rcu_assign_sk_user_data(clcsk, NULL);
|
||||
|
||||
smc_clcsock_restore_cb(&clcsk->sk_state_change, &smc->clcsk_state_change);
|
||||
smc_clcsock_restore_cb(&clcsk->sk_data_ready, &smc->clcsk_data_ready);
|
||||
@@ -902,7 +912,7 @@ static void smc_fback_replace_callbacks(struct smc_sock *smc)
|
||||
struct sock *clcsk = smc->clcsock->sk;
|
||||
|
||||
write_lock_bh(&clcsk->sk_callback_lock);
|
||||
clcsk->sk_user_data = (void *)((uintptr_t)smc | SK_USER_DATA_NOCOPY);
|
||||
__rcu_assign_sk_user_data_with_flags(clcsk, smc, SK_USER_DATA_NOCOPY);
|
||||
|
||||
smc_clcsock_replace_cb(&clcsk->sk_state_change, smc_fback_state_change,
|
||||
&smc->clcsk_state_change);
|
||||
@@ -2665,8 +2675,8 @@ int smc_listen(struct socket *sock, int backlog)
|
||||
* smc-specific sk_data_ready function
|
||||
*/
|
||||
write_lock_bh(&smc->clcsock->sk->sk_callback_lock);
|
||||
smc->clcsock->sk->sk_user_data =
|
||||
(void *)((uintptr_t)smc | SK_USER_DATA_NOCOPY);
|
||||
__rcu_assign_sk_user_data_with_flags(smc->clcsock->sk, smc,
|
||||
SK_USER_DATA_NOCOPY);
|
||||
smc_clcsock_replace_cb(&smc->clcsock->sk->sk_data_ready,
|
||||
smc_clcsock_data_ready, &smc->clcsk_data_ready);
|
||||
write_unlock_bh(&smc->clcsock->sk->sk_callback_lock);
|
||||
@@ -2687,10 +2697,11 @@ int smc_listen(struct socket *sock, int backlog)
|
||||
write_lock_bh(&smc->clcsock->sk->sk_callback_lock);
|
||||
smc_clcsock_restore_cb(&smc->clcsock->sk->sk_data_ready,
|
||||
&smc->clcsk_data_ready);
|
||||
smc->clcsock->sk->sk_user_data = NULL;
|
||||
rcu_assign_sk_user_data(smc->clcsock->sk, NULL);
|
||||
write_unlock_bh(&smc->clcsock->sk->sk_callback_lock);
|
||||
goto out;
|
||||
}
|
||||
sock_set_flag(sk, SOCK_RCU_FREE);
|
||||
sk->sk_max_ack_backlog = backlog;
|
||||
sk->sk_ack_backlog = 0;
|
||||
sk->sk_state = SMC_LISTEN;
|
||||
|
||||
@@ -346,6 +346,11 @@ static inline struct smc_sock *smc_clcsock_user_data(const struct sock *clcsk)
|
||||
((uintptr_t)clcsk->sk_user_data & ~SK_USER_DATA_NOCOPY);
|
||||
}
|
||||
|
||||
static inline struct smc_sock *smc_clcsock_user_data_rcu(const struct sock *clcsk)
|
||||
{
|
||||
return (struct smc_sock *)rcu_dereference_sk_user_data(clcsk);
|
||||
}
|
||||
|
||||
/* save target_cb in saved_cb, and replace target_cb with new_cb */
|
||||
static inline void smc_clcsock_replace_cb(void (**target_cb)(struct sock *),
|
||||
void (*new_cb)(struct sock *),
|
||||
|
||||
@@ -218,7 +218,7 @@ again:
|
||||
write_lock_bh(&smc->clcsock->sk->sk_callback_lock);
|
||||
smc_clcsock_restore_cb(&smc->clcsock->sk->sk_data_ready,
|
||||
&smc->clcsk_data_ready);
|
||||
smc->clcsock->sk->sk_user_data = NULL;
|
||||
rcu_assign_sk_user_data(smc->clcsock->sk, NULL);
|
||||
write_unlock_bh(&smc->clcsock->sk->sk_callback_lock);
|
||||
rc = kernel_sock_shutdown(smc->clcsock, SHUT_RDWR);
|
||||
}
|
||||
|
||||
@@ -1958,6 +1958,8 @@ static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb)
|
||||
static void unix_peek_fds(struct scm_cookie *scm, struct sk_buff *skb)
|
||||
{
|
||||
scm->fp = scm_fp_dup(UNIXCB(skb).fp);
|
||||
|
||||
unix_peek_fpl(scm->fp);
|
||||
}
|
||||
|
||||
static void unix_destruct_scm(struct sk_buff *skb)
|
||||
|
||||
@@ -29,6 +29,7 @@ void unix_del_edges(struct scm_fp_list *fpl);
|
||||
void unix_update_edges(struct unix_sock *receiver);
|
||||
int unix_prepare_fpl(struct scm_fp_list *fpl);
|
||||
void unix_destroy_fpl(struct scm_fp_list *fpl);
|
||||
void unix_peek_fpl(struct scm_fp_list *fpl);
|
||||
void unix_schedule_gc(struct user_struct *user);
|
||||
|
||||
/* SOCK_DIAG */
|
||||
|
||||
@@ -318,6 +318,25 @@ void unix_destroy_fpl(struct scm_fp_list *fpl)
|
||||
unix_free_vertices(fpl);
|
||||
}
|
||||
|
||||
static bool gc_in_progress;
|
||||
static seqcount_t unix_peek_seq = SEQCNT_ZERO(unix_peek_seq);
|
||||
|
||||
void unix_peek_fpl(struct scm_fp_list *fpl)
|
||||
{
|
||||
static DEFINE_SPINLOCK(unix_peek_lock);
|
||||
|
||||
if (!fpl || !fpl->count_unix)
|
||||
return;
|
||||
|
||||
if (!READ_ONCE(gc_in_progress))
|
||||
return;
|
||||
|
||||
/* Invalidate the final refcnt check in unix_vertex_dead(). */
|
||||
spin_lock(&unix_peek_lock);
|
||||
raw_write_seqcount_barrier(&unix_peek_seq);
|
||||
spin_unlock(&unix_peek_lock);
|
||||
}
|
||||
|
||||
static bool unix_vertex_dead(struct unix_vertex *vertex)
|
||||
{
|
||||
struct unix_edge *edge;
|
||||
@@ -351,6 +370,36 @@ static bool unix_vertex_dead(struct unix_vertex *vertex)
|
||||
return true;
|
||||
}
|
||||
|
||||
static LIST_HEAD(unix_visited_vertices);
|
||||
static unsigned long unix_vertex_grouped_index = UNIX_VERTEX_INDEX_MARK2;
|
||||
|
||||
static bool unix_scc_dead(struct list_head *scc, bool fast)
|
||||
{
|
||||
struct unix_vertex *vertex;
|
||||
bool scc_dead = true;
|
||||
unsigned int seq;
|
||||
|
||||
seq = read_seqcount_begin(&unix_peek_seq);
|
||||
|
||||
list_for_each_entry_reverse(vertex, scc, scc_entry) {
|
||||
/* Don't restart DFS from this vertex. */
|
||||
list_move_tail(&vertex->entry, &unix_visited_vertices);
|
||||
|
||||
/* Mark vertex as off-stack for __unix_walk_scc(). */
|
||||
if (!fast)
|
||||
vertex->index = unix_vertex_grouped_index;
|
||||
|
||||
if (scc_dead)
|
||||
scc_dead = unix_vertex_dead(vertex);
|
||||
}
|
||||
|
||||
/* If MSG_PEEK intervened, defer this SCC to the next round. */
|
||||
if (read_seqcount_retry(&unix_peek_seq, seq))
|
||||
return false;
|
||||
|
||||
return scc_dead;
|
||||
}
|
||||
|
||||
static void unix_collect_skb(struct list_head *scc, struct sk_buff_head *hitlist)
|
||||
{
|
||||
struct unix_vertex *vertex;
|
||||
@@ -404,9 +453,6 @@ static bool unix_scc_cyclic(struct list_head *scc)
|
||||
return false;
|
||||
}
|
||||
|
||||
static LIST_HEAD(unix_visited_vertices);
|
||||
static unsigned long unix_vertex_grouped_index = UNIX_VERTEX_INDEX_MARK2;
|
||||
|
||||
static unsigned long __unix_walk_scc(struct unix_vertex *vertex,
|
||||
unsigned long *last_index,
|
||||
struct sk_buff_head *hitlist)
|
||||
@@ -474,9 +520,7 @@ prev_vertex:
|
||||
}
|
||||
|
||||
if (vertex->index == vertex->scc_index) {
|
||||
struct unix_vertex *v;
|
||||
struct list_head scc;
|
||||
bool scc_dead = true;
|
||||
|
||||
/* SCC finalised.
|
||||
*
|
||||
@@ -485,18 +529,7 @@ prev_vertex:
|
||||
*/
|
||||
__list_cut_position(&scc, &vertex_stack, &vertex->scc_entry);
|
||||
|
||||
list_for_each_entry_reverse(v, &scc, scc_entry) {
|
||||
/* Don't restart DFS from this vertex in unix_walk_scc(). */
|
||||
list_move_tail(&v->entry, &unix_visited_vertices);
|
||||
|
||||
/* Mark vertex as off-stack. */
|
||||
v->index = unix_vertex_grouped_index;
|
||||
|
||||
if (scc_dead)
|
||||
scc_dead = unix_vertex_dead(v);
|
||||
}
|
||||
|
||||
if (scc_dead) {
|
||||
if (unix_scc_dead(&scc, false)) {
|
||||
unix_collect_skb(&scc, hitlist);
|
||||
} else {
|
||||
if (unix_vertex_max_scc_index < vertex->scc_index)
|
||||
@@ -550,19 +583,11 @@ static void unix_walk_scc_fast(struct sk_buff_head *hitlist)
|
||||
while (!list_empty(&unix_unvisited_vertices)) {
|
||||
struct unix_vertex *vertex;
|
||||
struct list_head scc;
|
||||
bool scc_dead = true;
|
||||
|
||||
vertex = list_first_entry(&unix_unvisited_vertices, typeof(*vertex), entry);
|
||||
list_add(&scc, &vertex->scc_entry);
|
||||
|
||||
list_for_each_entry_reverse(vertex, &scc, scc_entry) {
|
||||
list_move_tail(&vertex->entry, &unix_visited_vertices);
|
||||
|
||||
if (scc_dead)
|
||||
scc_dead = unix_vertex_dead(vertex);
|
||||
}
|
||||
|
||||
if (scc_dead) {
|
||||
if (unix_scc_dead(&scc, true)) {
|
||||
cyclic_sccs--;
|
||||
unix_collect_skb(&scc, hitlist);
|
||||
}
|
||||
@@ -577,8 +602,6 @@ static void unix_walk_scc_fast(struct sk_buff_head *hitlist)
|
||||
cyclic_sccs ? UNIX_GRAPH_CYCLIC : UNIX_GRAPH_NOT_CYCLIC);
|
||||
}
|
||||
|
||||
static bool gc_in_progress;
|
||||
|
||||
static void unix_gc(struct work_struct *work)
|
||||
{
|
||||
struct sk_buff_head hitlist;
|
||||
|
||||
@@ -664,6 +664,7 @@ void cfg80211_pmsr_wdev_down(struct wireless_dev *wdev)
|
||||
}
|
||||
spin_unlock_bh(&wdev->pmsr_lock);
|
||||
|
||||
cancel_work_sync(&wdev->pmsr_free_wk);
|
||||
if (found)
|
||||
cfg80211_pmsr_process_abort(wdev);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user