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

Pull networking fixes from Paolo Abeni:
 "Including fixes from netfilter, IPsec and wireless. This is again
  considerably bigger than the old average. No known outstanding
  regressions.

  Current release - regressions:

   - net: increase IP_TUNNEL_RECURSION_LIMIT to 5

   - eth: ice: fix PTP timestamping broken by SyncE code on E825C

  Current release - new code bugs:

   - eth: stmmac: dwmac-motorcomm: fix eFUSE MAC address read failure

  Previous releases - regressions:

   - core: fix cross-cache free of KFENCE-allocated skb head

   - sched: act_csum: validate nested VLAN headers

   - rxrpc: fix call removal to use RCU safe deletion

   - xfrm:
      - wait for RCU readers during policy netns exit
      - fix refcount leak in xfrm_migrate_policy_find

   - wifi: rt2x00usb: fix devres lifetime

   - mptcp: fix slab-use-after-free in __inet_lookup_established

   - ipvs: fix NULL deref in ip_vs_add_service error path

   - eth:
      - airoha: fix memory leak in airoha_qdma_rx_process()
      - lan966x: fix use-after-free and leak in lan966x_fdma_reload()

  Previous releases - always broken:

   - ipv6: ioam: fix potential NULL dereferences in __ioam6_fill_trace_data()

   - ipv4: nexthop: avoid duplicate NHA_HW_STATS_ENABLE on nexthop group
     dump

   - bridge: guard local VLAN-0 FDB helpers against NULL vlan group

   - xsk: tailroom reservation and MTU validation

   - rxrpc:
      - fix to request an ack if window is limited
      - fix RESPONSE authenticator parser OOB read

   - netfilter: nft_ct: fix use-after-free in timeout object destroy

   - batman-adv: hold claim backbone gateways by reference

   - eth:
      - stmmac: fix PTP ref clock for Tegra234
      - idpf: fix PREEMPT_RT raw/bh spinlock nesting for async VC handling
      - ipa: fix GENERIC_CMD register field masks for IPA v5.0+"

* tag 'net-7.0-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (104 commits)
  net: lan966x: fix use-after-free and leak in lan966x_fdma_reload()
  net: lan966x: fix page pool leak in error paths
  net: lan966x: fix page_pool error handling in lan966x_fdma_rx_alloc_page_pool()
  nfc: pn533: allocate rx skb before consuming bytes
  l2tp: Drop large packets with UDP encap
  net: ipa: fix event ring index not programmed for IPA v5.0+
  net: ipa: fix GENERIC_CMD register field masks for IPA v5.0+
  MAINTAINERS: Add Prashanth as additional maintainer for amd-xgbe driver
  devlink: Fix incorrect skb socket family dumping
  af_unix: read UNIX_DIAG_VFS data under unix_state_lock
  Revert "mptcp: add needs_id for netlink appending addr"
  mptcp: fix slab-use-after-free in __inet_lookup_established
  net: txgbe: leave space for null terminators on property_entry
  net: ioam6: fix OOB and missing lock
  rxrpc: proc: size address buffers for %pISpc output
  rxrpc: only handle RESPONSE during service challenge
  rxrpc: Fix buffer overread in rxgk_do_verify_authenticator()
  rxrpc: Fix leak of rxgk context in rxgk_verify_response()
  rxrpc: Fix integer overflow in rxgk_verify_response()
  rxrpc: Fix missing error checks for rxkad encryption/decryption failure
  ...
This commit is contained in:
Linus Torvalds
2026-04-09 08:39:25 -07:00
97 changed files with 1172 additions and 468 deletions

View File

@@ -42,7 +42,7 @@ properties:
- const: mgbe
- const: mac
- const: mac-divider
- const: ptp-ref
- const: ptp_ref
- const: rx-input-m
- const: rx-input
- const: tx
@@ -133,7 +133,7 @@ examples:
<&bpmp TEGRA234_CLK_MGBE0_RX_PCS_M>,
<&bpmp TEGRA234_CLK_MGBE0_RX_PCS>,
<&bpmp TEGRA234_CLK_MGBE0_TX_PCS>;
clock-names = "mgbe", "mac", "mac-divider", "ptp-ref", "rx-input-m",
clock-names = "mgbe", "mac", "mac-divider", "ptp_ref", "rx-input-m",
"rx-input", "tx", "eee-pcs", "rx-pcs-input", "rx-pcs-m",
"rx-pcs", "tx-pcs";
resets = <&bpmp TEGRA234_RESET_MGBE0_MAC>,

View File

@@ -1291,6 +1291,7 @@ F: include/uapi/drm/amdxdna_accel.h
AMD XGBE DRIVER
M: Raju Rangoju <Raju.Rangoju@amd.com>
M: Prashanth Kumar K R <PrashanthKumar.K.R@amd.com>
L: netdev@vger.kernel.org
S: Maintained
F: arch/arm64/boot/dts/amd/amd-seattle-xgbe*.dtsi
@@ -21075,8 +21076,7 @@ F: include/uapi/linux/atmppp.h
F: net/atm/pppoatm.c
PPP OVER ETHERNET
M: Michal Ostrowski <mostrows@earthlink.net>
S: Maintained
S: Orphan
F: drivers/net/ppp/pppoe.c
F: drivers/net/ppp/pppox.c
@@ -22130,7 +22130,7 @@ S: Supported
F: drivers/infiniband/sw/rdmavt
RDS - RELIABLE DATAGRAM SOCKETS
M: Allison Henderson <allison.henderson@oracle.com>
M: Allison Henderson <achender@kernel.org>
L: netdev@vger.kernel.org
L: linux-rdma@vger.kernel.org
L: rds-devel@oss.oracle.com (moderated for non-subscribers)

View File

@@ -697,9 +697,8 @@ free_frag:
if (q->skb) {
dev_kfree_skb(q->skb);
q->skb = NULL;
} else {
page_pool_put_full_page(q->page_pool, page, true);
}
page_pool_put_full_page(q->page_pool, page, true);
}
airoha_qdma_fill_rx_queue(q);

View File

@@ -570,6 +570,7 @@ static netdev_tx_t tse_start_xmit(struct sk_buff *skb, struct net_device *dev)
DMA_TO_DEVICE);
if (dma_mapping_error(priv->device, dma_addr)) {
netdev_err(priv->dev, "%s: DMA mapping error\n", __func__);
dev_kfree_skb_any(skb);
ret = NETDEV_TX_OK;
goto out;
}

View File

@@ -28,7 +28,7 @@ config FEC
depends on PTP_1588_CLOCK_OPTIONAL
select CRC32
select PHYLIB
select FIXED_PHY if M5272
select FIXED_PHY
select PAGE_POOL
imply PAGE_POOL_STATS
imply NET_SELFTESTS

View File

@@ -496,14 +496,19 @@ static int e1000_set_eeprom(struct net_device *netdev,
*/
ret_val = e1000_read_eeprom(hw, first_word, 1,
&eeprom_buff[0]);
if (ret_val)
goto out;
ptr++;
}
if (((eeprom->offset + eeprom->len) & 1) && (ret_val == 0)) {
if ((eeprom->offset + eeprom->len) & 1) {
/* need read/modify/write of last changed EEPROM word
* only the first byte of the word is being modified
*/
ret_val = e1000_read_eeprom(hw, last_word, 1,
&eeprom_buff[last_word - first_word]);
if (ret_val)
goto out;
}
/* Device's eeprom is always little-endian, word addressable */
@@ -522,6 +527,7 @@ static int e1000_set_eeprom(struct net_device *netdev,
if ((ret_val == 0) && (first_word <= EEPROM_CHECKSUM_REG))
e1000_update_eeprom_checksum(hw);
out:
kfree(eeprom_buff);
return ret_val;
}

View File

@@ -1296,12 +1296,10 @@ void ice_ptp_link_change(struct ice_pf *pf, bool linkup)
if (pf->hw.reset_ongoing)
return;
if (hw->mac_type == ICE_MAC_GENERIC_3K_E825) {
if (hw->mac_type == ICE_MAC_GENERIC_3K_E825 &&
test_bit(ICE_FLAG_DPLL, pf->flags)) {
int pin, err;
if (!test_bit(ICE_FLAG_DPLL, pf->flags))
return;
mutex_lock(&pf->dplls.lock);
for (pin = 0; pin < ICE_SYNCE_CLK_NUM; pin++) {
enum ice_synce_clk clk_pin;
@@ -1314,15 +1312,19 @@ void ice_ptp_link_change(struct ice_pf *pf, bool linkup)
port_num,
&active,
clk_pin);
if (WARN_ON_ONCE(err)) {
mutex_unlock(&pf->dplls.lock);
return;
if (err) {
dev_err_once(ice_pf_to_dev(pf),
"Failed to read SyncE bypass mux for pin %d, err %d\n",
pin, err);
break;
}
err = ice_tspll_cfg_synce_ethdiv_e825c(hw, clk_pin);
if (active && WARN_ON_ONCE(err)) {
mutex_unlock(&pf->dplls.lock);
return;
if (active && err) {
dev_err_once(ice_pf_to_dev(pf),
"Failed to configure SyncE ETH divider for pin %d, err %d\n",
pin, err);
break;
}
}
mutex_unlock(&pf->dplls.lock);
@@ -3080,7 +3082,13 @@ static int ice_ptp_setup_pf(struct ice_pf *pf)
struct ice_ptp *ctrl_ptp = ice_get_ctrl_ptp(pf);
struct ice_ptp *ptp = &pf->ptp;
if (WARN_ON(!ctrl_ptp) || pf->hw.mac_type == ICE_MAC_UNKNOWN)
if (!ctrl_ptp) {
dev_info(ice_pf_to_dev(pf),
"PTP unavailable: no controlling PF\n");
return -EOPNOTSUPP;
}
if (pf->hw.mac_type == ICE_MAC_UNKNOWN)
return -ENODEV;
INIT_LIST_HEAD(&ptp->port.list_node);

View File

@@ -287,26 +287,21 @@ dma_mem_error:
return err;
}
/* API for virtchnl "transaction" support ("xn" for short).
*
* We are reusing the completion lock to serialize the accesses to the
* transaction state for simplicity, but it could be its own separate synchro
* as well. For now, this API is only used from within a workqueue context;
* raw_spin_lock() is enough.
*/
/* API for virtchnl "transaction" support ("xn" for short). */
/**
* idpf_vc_xn_lock - Request exclusive access to vc transaction
* @xn: struct idpf_vc_xn* to access
*/
#define idpf_vc_xn_lock(xn) \
raw_spin_lock(&(xn)->completed.wait.lock)
spin_lock(&(xn)->lock)
/**
* idpf_vc_xn_unlock - Release exclusive access to vc transaction
* @xn: struct idpf_vc_xn* to access
*/
#define idpf_vc_xn_unlock(xn) \
raw_spin_unlock(&(xn)->completed.wait.lock)
spin_unlock(&(xn)->lock)
/**
* idpf_vc_xn_release_bufs - Release reference to reply buffer(s) and
@@ -338,6 +333,7 @@ static void idpf_vc_xn_init(struct idpf_vc_xn_manager *vcxn_mngr)
xn->state = IDPF_VC_XN_IDLE;
xn->idx = i;
idpf_vc_xn_release_bufs(xn);
spin_lock_init(&xn->lock);
init_completion(&xn->completed);
}
@@ -406,7 +402,9 @@ static void idpf_vc_xn_push_free(struct idpf_vc_xn_manager *vcxn_mngr,
struct idpf_vc_xn *xn)
{
idpf_vc_xn_release_bufs(xn);
spin_lock_bh(&vcxn_mngr->xn_bm_lock);
set_bit(xn->idx, vcxn_mngr->free_xn_bm);
spin_unlock_bh(&vcxn_mngr->xn_bm_lock);
}
/**
@@ -617,6 +615,10 @@ idpf_vc_xn_forward_reply(struct idpf_adapter *adapter,
err = -ENXIO;
goto out_unlock;
case IDPF_VC_XN_ASYNC:
/* Set reply_sz from the actual payload so that async_handler
* can evaluate the response.
*/
xn->reply_sz = ctlq_msg->data_len;
err = idpf_vc_xn_forward_async(adapter, xn, ctlq_msg);
idpf_vc_xn_unlock(xn);
return err;

View File

@@ -42,8 +42,8 @@ typedef int (*async_vc_cb) (struct idpf_adapter *, struct idpf_vc_xn *,
* struct idpf_vc_xn - Data structure representing virtchnl transactions
* @completed: virtchnl event loop uses that to signal when a reply is
* available, uses kernel completion API
* @state: virtchnl event loop stores the data below, protected by the
* completion's lock.
* @lock: protects the transaction state fields below
* @state: virtchnl event loop stores the data below, protected by @lock
* @reply_sz: Original size of reply, may be > reply_buf.iov_len; it will be
* truncated on its way to the receiver thread according to
* reply_buf.iov_len.
@@ -58,6 +58,7 @@ typedef int (*async_vc_cb) (struct idpf_adapter *, struct idpf_vc_xn *,
*/
struct idpf_vc_xn {
struct completion completed;
spinlock_t lock;
enum idpf_vc_xn_state state;
size_t reply_sz;
struct kvec reply;

View File

@@ -2203,9 +2203,8 @@ void igb_down(struct igb_adapter *adapter)
for (i = 0; i < adapter->num_q_vectors; i++) {
if (adapter->q_vector[i]) {
napi_synchronize(&adapter->q_vector[i]->napi);
igb_set_queue_napi(adapter, i, NULL);
napi_disable(&adapter->q_vector[i]->napi);
igb_set_queue_napi(adapter, i, NULL);
}
}

View File

@@ -474,7 +474,7 @@ static int ixgbe_devlink_reload_empr_finish(struct devlink *devlink,
adapter->flags2 &= ~(IXGBE_FLAG2_API_MISMATCH |
IXGBE_FLAG2_FW_ROLLBACK);
return 0;
return ixgbe_refresh_fw_version(adapter);
}
static const struct devlink_ops ixgbe_devlink_ops = {

View File

@@ -973,7 +973,7 @@ int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter);
bool ixgbe_wol_supported(struct ixgbe_adapter *adapter, u16 device_id,
u16 subdevice_id);
void ixgbe_set_fw_version_e610(struct ixgbe_adapter *adapter);
void ixgbe_refresh_fw_version(struct ixgbe_adapter *adapter);
int ixgbe_refresh_fw_version(struct ixgbe_adapter *adapter);
#ifdef CONFIG_PCI_IOV
void ixgbe_full_sync_mac_table(struct ixgbe_adapter *adapter);
#endif

View File

@@ -1155,12 +1155,17 @@ err:
return ret_val;
}
void ixgbe_refresh_fw_version(struct ixgbe_adapter *adapter)
int ixgbe_refresh_fw_version(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
int err;
err = ixgbe_get_flash_data(hw);
if (err)
return err;
ixgbe_get_flash_data(hw);
ixgbe_set_fw_version_e610(adapter);
return 0;
}
static void ixgbe_get_drvinfo(struct net_device *netdev,
@@ -1168,10 +1173,6 @@ static void ixgbe_get_drvinfo(struct net_device *netdev,
{
struct ixgbe_adapter *adapter = ixgbe_from_netdev(netdev);
/* need to refresh info for e610 in case fw reloads in runtime */
if (adapter->hw.mac.type == ixgbe_mac_e610)
ixgbe_refresh_fw_version(adapter);
strscpy(drvinfo->driver, ixgbe_driver_name, sizeof(drvinfo->driver));
strscpy(drvinfo->fw_version, adapter->eeprom_id,

View File

@@ -6289,6 +6289,16 @@ void ixgbe_reinit_locked(struct ixgbe_adapter *adapter)
if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
msleep(2000);
ixgbe_up(adapter);
/* E610 has no FW event to notify all PFs of an EMPR reset, so
* refresh the FW version here to pick up any new FW version after
* a hardware reset (e.g. EMPR triggered by another PF's devlink
* reload). ixgbe_refresh_fw_version() updates both hw->flash and
* adapter->eeprom_id so ethtool -i reports the correct string.
*/
if (adapter->hw.mac.type == ixgbe_mac_e610)
(void)ixgbe_refresh_fw_version(adapter);
clear_bit(__IXGBE_RESETTING, &adapter->state);
}

View File

@@ -709,6 +709,12 @@ static int ixgbevf_negotiate_features_vf(struct ixgbe_hw *hw, u32 *pf_features)
return err;
}
static int ixgbevf_hv_negotiate_features_vf(struct ixgbe_hw *hw,
u32 *pf_features)
{
return -EOPNOTSUPP;
}
/**
* ixgbevf_set_vfta_vf - Set/Unset VLAN filter table address
* @hw: pointer to the HW structure
@@ -1142,6 +1148,7 @@ static const struct ixgbe_mac_operations ixgbevf_hv_mac_ops = {
.setup_link = ixgbevf_setup_mac_link_vf,
.check_link = ixgbevf_hv_check_mac_link_vf,
.negotiate_api_version = ixgbevf_hv_negotiate_api_version_vf,
.negotiate_features = ixgbevf_hv_negotiate_features_vf,
.set_rar = ixgbevf_hv_set_rar_vf,
.update_mc_addr_list = ixgbevf_hv_update_mc_addr_list_vf,
.update_xcast_mode = ixgbevf_hv_update_xcast_mode,

View File

@@ -2267,6 +2267,7 @@ static const struct pci_device_id mlx5_core_pci_table[] = {
{ PCI_VDEVICE(MELLANOX, 0x1023) }, /* ConnectX-8 */
{ PCI_VDEVICE(MELLANOX, 0x1025) }, /* ConnectX-9 */
{ PCI_VDEVICE(MELLANOX, 0x1027) }, /* ConnectX-10 */
{ PCI_VDEVICE(MELLANOX, 0x2101) }, /* ConnectX-10 NVLink-C2C */
{ PCI_VDEVICE(MELLANOX, 0xa2d2) }, /* BlueField integrated ConnectX-5 network controller */
{ PCI_VDEVICE(MELLANOX, 0xa2d3), MLX5_PCI_DEV_IS_VF}, /* BlueField integrated ConnectX-5 network controller VF */
{ PCI_VDEVICE(MELLANOX, 0xa2d6) }, /* BlueField-2 integrated ConnectX-6 Dx network controller */

View File

@@ -91,6 +91,8 @@ static int lan966x_fdma_rx_alloc_page_pool(struct lan966x_rx *rx)
pp_params.dma_dir = DMA_BIDIRECTIONAL;
rx->page_pool = page_pool_create(&pp_params);
if (unlikely(IS_ERR(rx->page_pool)))
return PTR_ERR(rx->page_pool);
for (int i = 0; i < lan966x->num_phys_ports; ++i) {
struct lan966x_port *port;
@@ -117,8 +119,10 @@ static int lan966x_fdma_rx_alloc(struct lan966x_rx *rx)
return PTR_ERR(rx->page_pool);
err = fdma_alloc_coherent(lan966x->dev, fdma);
if (err)
if (err) {
page_pool_destroy(rx->page_pool);
return err;
}
fdma_dcbs_init(fdma, FDMA_DCB_INFO_DATAL(fdma->db_size),
FDMA_DCB_STATUS_INTR);
@@ -808,9 +812,15 @@ static int lan966x_qsys_sw_status(struct lan966x *lan966x)
static int lan966x_fdma_reload(struct lan966x *lan966x, int new_mtu)
{
struct page *(*old_pages)[FDMA_RX_DCB_MAX_DBS];
struct page_pool *page_pool;
struct fdma fdma_rx_old;
int err;
int err, i, j;
old_pages = kmemdup(lan966x->rx.page, sizeof(lan966x->rx.page),
GFP_KERNEL);
if (!old_pages)
return -ENOMEM;
/* Store these for later to free them */
memcpy(&fdma_rx_old, &lan966x->rx.fdma, sizeof(struct fdma));
@@ -821,7 +831,6 @@ static int lan966x_fdma_reload(struct lan966x *lan966x, int new_mtu)
lan966x_fdma_stop_netdev(lan966x);
lan966x_fdma_rx_disable(&lan966x->rx);
lan966x_fdma_rx_free_pages(&lan966x->rx);
lan966x->rx.page_order = round_up(new_mtu, PAGE_SIZE) / PAGE_SIZE - 1;
lan966x->rx.max_mtu = new_mtu;
err = lan966x_fdma_rx_alloc(&lan966x->rx);
@@ -829,6 +838,11 @@ static int lan966x_fdma_reload(struct lan966x *lan966x, int new_mtu)
goto restore;
lan966x_fdma_rx_start(&lan966x->rx);
for (i = 0; i < fdma_rx_old.n_dcbs; ++i)
for (j = 0; j < fdma_rx_old.n_dbs; ++j)
page_pool_put_full_page(page_pool,
old_pages[i][j], false);
fdma_free_coherent(lan966x->dev, &fdma_rx_old);
page_pool_destroy(page_pool);
@@ -836,12 +850,17 @@ static int lan966x_fdma_reload(struct lan966x *lan966x, int new_mtu)
lan966x_fdma_wakeup_netdev(lan966x);
napi_enable(&lan966x->napi);
return err;
kfree(old_pages);
return 0;
restore:
lan966x->rx.page_pool = page_pool;
memcpy(&lan966x->rx.fdma, &fdma_rx_old, sizeof(struct fdma));
lan966x_fdma_rx_start(&lan966x->rx);
lan966x_fdma_wakeup_netdev(lan966x);
napi_enable(&lan966x->napi);
kfree(old_pages);
return err;
}
@@ -955,6 +974,7 @@ int lan966x_fdma_init(struct lan966x *lan966x)
err = lan966x_fdma_tx_alloc(&lan966x->tx);
if (err) {
fdma_free_coherent(lan966x->dev, &lan966x->rx.fdma);
page_pool_destroy(lan966x->rx.page_pool);
return err;
}

View File

@@ -100,7 +100,7 @@ qca_tty_receive(struct serdev_device *serdev, const u8 *data, size_t count)
if (!qca->rx_skb) {
netdev_dbg(netdev, "recv: out of RX resources\n");
n_stats->rx_errors++;
return i;
return i + 1;
}
}
}

View File

@@ -20,7 +20,7 @@ static int jumbo_frm(struct stmmac_tx_queue *tx_q, struct sk_buff *skb,
unsigned int nopaged_len = skb_headlen(skb);
struct stmmac_priv *priv = tx_q->priv_data;
unsigned int entry = tx_q->cur_tx;
unsigned int bmax, des2;
unsigned int bmax, buf_len, des2;
unsigned int i = 1, len;
struct dma_desc *desc;
@@ -31,17 +31,18 @@ static int jumbo_frm(struct stmmac_tx_queue *tx_q, struct sk_buff *skb,
else
bmax = BUF_SIZE_2KiB;
len = nopaged_len - bmax;
buf_len = min_t(unsigned int, nopaged_len, bmax);
len = nopaged_len - buf_len;
des2 = dma_map_single(priv->device, skb->data,
bmax, DMA_TO_DEVICE);
buf_len, DMA_TO_DEVICE);
desc->des2 = cpu_to_le32(des2);
if (dma_mapping_error(priv->device, des2))
return -1;
tx_q->tx_skbuff_dma[entry].buf = des2;
tx_q->tx_skbuff_dma[entry].len = bmax;
tx_q->tx_skbuff_dma[entry].len = buf_len;
/* do not close the descriptor and do not set own bit */
stmmac_prepare_tx_desc(priv, desc, 1, bmax, csum, STMMAC_CHAIN_MODE,
stmmac_prepare_tx_desc(priv, desc, 1, buf_len, csum, STMMAC_CHAIN_MODE,
0, false, skb->len);
while (len != 0) {

View File

@@ -6,6 +6,7 @@
*/
#include <linux/bits.h>
#include <linux/delay.h>
#include <linux/dev_printk.h>
#include <linux/io.h>
#include <linux/iopoll.h>
@@ -334,6 +335,13 @@ static int motorcomm_probe(struct pci_dev *pdev, const struct pci_device_id *id)
motorcomm_reset(priv);
/*
* After system reset, the eFuse controller needs time to load
* its internal data. Without this delay, eFuse reads return
* all zeros, causing MAC address detection to fail.
*/
usleep_range(2000, 5000);
ret = motorcomm_efuse_read_mac(&pdev->dev, priv, res.mac);
if (ret == -ENOENT) {
dev_warn(&pdev->dev, "eFuse contains no valid MAC address\n");

View File

@@ -9,7 +9,7 @@
#include "stmmac_platform.h"
static const char *const mgbe_clks[] = {
"rx-pcs", "tx", "tx-pcs", "mac-divider", "mac", "mgbe", "ptp-ref", "mac"
"rx-pcs", "tx", "tx-pcs", "mac-divider", "mac", "mgbe", "ptp_ref", "mac"
};
struct tegra_mgbe {
@@ -215,6 +215,7 @@ static int tegra_mgbe_probe(struct platform_device *pdev)
{
struct plat_stmmacenet_data *plat;
struct stmmac_resources res;
bool use_legacy_ptp = false;
struct tegra_mgbe *mgbe;
int irq, err, i;
u32 value;
@@ -257,9 +258,23 @@ static int tegra_mgbe_probe(struct platform_device *pdev)
if (!mgbe->clks)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(mgbe_clks); i++)
/* Older device-trees use 'ptp-ref' rather than 'ptp_ref'.
* Fall back when the legacy name is present.
*/
if (of_property_match_string(pdev->dev.of_node, "clock-names",
"ptp-ref") >= 0)
use_legacy_ptp = true;
for (i = 0; i < ARRAY_SIZE(mgbe_clks); i++) {
mgbe->clks[i].id = mgbe_clks[i];
if (use_legacy_ptp && !strcmp(mgbe_clks[i], "ptp_ref")) {
dev_warn(mgbe->dev,
"Device-tree update needed for PTP clock!\n");
mgbe->clks[i].id = "ptp-ref";
}
}
err = devm_clk_bulk_get(mgbe->dev, ARRAY_SIZE(mgbe_clks), mgbe->clks);
if (err < 0)
return err;

View File

@@ -424,10 +424,10 @@ struct txgbe_nodes {
char i2c_name[32];
char sfp_name[32];
char phylink_name[32];
struct property_entry gpio_props[1];
struct property_entry i2c_props[3];
struct property_entry sfp_props[8];
struct property_entry phylink_props[2];
struct property_entry gpio_props[2];
struct property_entry i2c_props[4];
struct property_entry sfp_props[9];
struct property_entry phylink_props[3];
struct software_node_ref_args i2c_ref[1];
struct software_node_ref_args gpio0_ref[1];
struct software_node_ref_args gpio1_ref[1];

View File

@@ -30,7 +30,7 @@ REG_STRIDE_FIELDS(CH_C_CNTXT_0, ch_c_cntxt_0,
static const u32 reg_ch_c_cntxt_1_fmask[] = {
[CH_R_LENGTH] = GENMASK(23, 0),
[ERINDEX] = GENMASK(31, 24),
[CH_ERINDEX] = GENMASK(31, 24),
};
REG_STRIDE_FIELDS(CH_C_CNTXT_1, ch_c_cntxt_1,
@@ -156,9 +156,10 @@ REG_FIELDS(EV_CH_CMD, ev_ch_cmd, 0x00025010 + 0x12000 * GSI_EE_AP);
static const u32 reg_generic_cmd_fmask[] = {
[GENERIC_OPCODE] = GENMASK(4, 0),
[GENERIC_CHID] = GENMASK(9, 5),
[GENERIC_EE] = GENMASK(13, 10),
/* Bits 14-31 reserved */
[GENERIC_CHID] = GENMASK(12, 5),
[GENERIC_EE] = GENMASK(16, 13),
/* Bits 17-23 reserved */
[GENERIC_PARAMS] = GENMASK(31, 24),
};
REG_FIELDS(GENERIC_CMD, generic_cmd, 0x00025018 + 0x12000 * GSI_EE_AP);

View File

@@ -466,7 +466,6 @@ static int rtl9300_mdiobus_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct rtl9300_mdio_priv *priv;
struct fwnode_handle *child;
int err;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -487,7 +486,7 @@ static int rtl9300_mdiobus_probe(struct platform_device *pdev)
if (err)
return err;
device_for_each_child_node(dev, child) {
device_for_each_child_node_scoped(dev, child) {
err = rtl9300_mdiobus_probe_one(dev, priv, child);
if (err)
return err;

View File

@@ -543,6 +543,22 @@ static const struct sfp_quirk sfp_quirks[] = {
SFP_QUIRK("HUAWEI", "MA5671A", sfp_quirk_2500basex,
sfp_fixup_ignore_tx_fault_and_los),
// Hisense LXT-010S-H is a GPON ONT SFP (sold as LEOX LXT-010S-H) that
// can operate at 2500base-X, but reports 1000BASE-LX / 1300MBd in its
// EEPROM
SFP_QUIRK("Hisense-Leox", "LXT-010S-H", sfp_quirk_2500basex,
sfp_fixup_ignore_tx_fault),
// Hisense ZNID-GPON-2311NA can operate at 2500base-X, but reports
// 1000BASE-LX / 1300MBd in its EEPROM
SFP_QUIRK("Hisense", "ZNID-GPON-2311NA", sfp_quirk_2500basex,
sfp_fixup_ignore_tx_fault),
// HSGQ HSGQ-XPON-Stick can operate at 2500base-X, but reports
// 1000BASE-LX / 1300MBd in its EEPROM
SFP_QUIRK("HSGQ", "HSGQ-XPON-Stick", sfp_quirk_2500basex,
sfp_fixup_ignore_tx_fault),
// Lantech 8330-262D-E and 8330-265D can operate at 2500base-X, but
// incorrectly report 2500MBd NRZ in their EEPROM.
// Some 8330-265D modules have inverted LOS, while all of them report

View File

@@ -446,33 +446,36 @@ static void lapbeth_free_device(struct lapbethdev *lapbeth)
static int lapbeth_device_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct lapbethdev *lapbeth;
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct lapbethdev *lapbeth;
if (dev_net(dev) != &init_net)
return NOTIFY_DONE;
if (!dev_is_ethdev(dev) && !lapbeth_get_x25_dev(dev))
lapbeth = lapbeth_get_x25_dev(dev);
if (!dev_is_ethdev(dev) && !lapbeth)
return NOTIFY_DONE;
switch (event) {
case NETDEV_UP:
/* New ethernet device -> new LAPB interface */
if (!lapbeth_get_x25_dev(dev))
if (!lapbeth)
lapbeth_new_device(dev);
break;
case NETDEV_GOING_DOWN:
/* ethernet device closes -> close LAPB interface */
lapbeth = lapbeth_get_x25_dev(dev);
if (lapbeth)
dev_close(lapbeth->axdev);
break;
case NETDEV_UNREGISTER:
/* ethernet device disappears -> remove LAPB interface */
lapbeth = lapbeth_get_x25_dev(dev);
if (lapbeth)
lapbeth_free_device(lapbeth);
break;
case NETDEV_PRE_TYPE_CHANGE:
/* Our underlying device type must not change. */
if (lapbeth)
return NOTIFY_BAD;
}
return NOTIFY_DONE;

View File

@@ -153,6 +153,11 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
bphy_err(drvr, "invalid interface index: %u\n", ifevent->ifidx);
return;
}
if (ifevent->bsscfgidx >= BRCMF_MAX_IFS) {
bphy_err(drvr, "invalid bsscfg index: %u\n",
ifevent->bsscfgidx);
return;
}
ifp = drvr->iflist[ifevent->bsscfgidx];

View File

@@ -483,7 +483,7 @@ static void *dma_ringalloc(struct dma_info *di, u32 boundary, uint size,
if (((desc_strtaddr + size - 1) & boundary) != (desc_strtaddr
& boundary)) {
*alignbits = dma_align_sizetobits(size);
dma_free_coherent(di->dmadev, size, va, *descpa);
dma_free_coherent(di->dmadev, *alloced, va, *descpa);
va = dma_alloc_consistent(di, size, *alignbits,
alloced, descpa);
}

View File

@@ -828,7 +828,7 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
if (retval)
goto exit_free_device;
rt2x00dev->anchor = devm_kmalloc(&usb_dev->dev,
rt2x00dev->anchor = devm_kmalloc(&usb_intf->dev,
sizeof(struct usb_anchor),
GFP_KERNEL);
if (!rt2x00dev->anchor) {

View File

@@ -211,6 +211,13 @@ static size_t pn532_receive_buf(struct serdev_device *serdev,
timer_delete(&dev->cmd_timeout);
for (i = 0; i < count; i++) {
if (!dev->recv_skb) {
dev->recv_skb = alloc_skb(PN532_UART_SKB_BUFF_LEN,
GFP_KERNEL);
if (!dev->recv_skb)
return i;
}
if (unlikely(!skb_tailroom(dev->recv_skb)))
skb_trim(dev->recv_skb, 0);
@@ -219,9 +226,7 @@ static size_t pn532_receive_buf(struct serdev_device *serdev,
continue;
pn533_recv_frame(dev->priv, dev->recv_skb, 0);
dev->recv_skb = alloc_skb(PN532_UART_SKB_BUFF_LEN, GFP_KERNEL);
if (!dev->recv_skb)
return 0;
dev->recv_skb = NULL;
}
return i;

View File

@@ -58,6 +58,12 @@ static size_t s3fwrn82_uart_read(struct serdev_device *serdev,
size_t i;
for (i = 0; i < count; i++) {
if (!phy->recv_skb) {
phy->recv_skb = alloc_skb(NCI_SKB_BUFF_LEN, GFP_KERNEL);
if (!phy->recv_skb)
return i;
}
skb_put_u8(phy->recv_skb, *data++);
if (phy->recv_skb->len < S3FWRN82_NCI_HEADER)
@@ -69,9 +75,7 @@ static size_t s3fwrn82_uart_read(struct serdev_device *serdev,
s3fwrn5_recv_frame(phy->common.ndev, phy->recv_skb,
phy->common.mode);
phy->recv_skb = alloc_skb(NCI_SKB_BUFF_LEN, GFP_KERNEL);
if (!phy->recv_skb)
return 0;
phy->recv_skb = NULL;
}
return i;

View File

@@ -32,7 +32,7 @@
* recursion involves route lookups and full IP output, consuming much
* more stack per level, so a lower limit is needed.
*/
#define IP_TUNNEL_RECURSION_LIMIT 4
#define IP_TUNNEL_RECURSION_LIMIT 5
/* Keep error state on tunnel for 30 sec */
#define IPTUNNEL_ERR_TIMEO (30*HZ)

View File

@@ -14,6 +14,7 @@
struct nf_ct_timeout {
__u16 l3num;
const struct nf_conntrack_l4proto *l4proto;
struct rcu_head rcu;
char data[];
};

View File

@@ -23,7 +23,6 @@ struct nf_queue_entry {
struct nf_hook_state state;
bool nf_ct_is_unconfirmed;
u16 size; /* sizeof(entry) + saved route keys */
u16 queue_num;
/* extra space to store route keys */
};

View File

@@ -14,7 +14,7 @@
#include <linux/mm.h>
#include <net/sock.h>
#define XDP_UMEM_SG_FLAG (1 << 1)
#define XDP_UMEM_SG_FLAG BIT(3)
struct net_device;
struct xsk_queue;

View File

@@ -41,16 +41,37 @@ static inline u32 xsk_pool_get_headroom(struct xsk_buff_pool *pool)
return XDP_PACKET_HEADROOM + pool->headroom;
}
static inline u32 xsk_pool_get_tailroom(bool mbuf)
{
return mbuf ? SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) : 0;
}
static inline u32 xsk_pool_get_chunk_size(struct xsk_buff_pool *pool)
{
return pool->chunk_size;
}
static inline u32 xsk_pool_get_rx_frame_size(struct xsk_buff_pool *pool)
static inline u32 __xsk_pool_get_rx_frame_size(struct xsk_buff_pool *pool)
{
return xsk_pool_get_chunk_size(pool) - xsk_pool_get_headroom(pool);
}
static inline u32 xsk_pool_get_rx_frame_size(struct xsk_buff_pool *pool)
{
u32 frame_size = __xsk_pool_get_rx_frame_size(pool);
struct xdp_umem *umem = pool->umem;
bool mbuf;
/* Reserve tailroom only for zero-copy pools that opted into
* multi-buffer. The reserved area is used for skb_shared_info,
* matching the XDP core's xdp_data_hard_end() layout.
*/
mbuf = pool->dev && (umem->flags & XDP_UMEM_SG_FLAG);
frame_size -= xsk_pool_get_tailroom(mbuf);
return ALIGN_DOWN(frame_size, 128);
}
static inline u32 xsk_pool_get_rx_frag_step(struct xsk_buff_pool *pool)
{
return pool->unaligned ? 0 : xsk_pool_get_chunk_size(pool);

View File

@@ -185,6 +185,7 @@
EM(rxrpc_skb_put_input, "PUT input ") \
EM(rxrpc_skb_put_jumbo_subpacket, "PUT jumbo-sub") \
EM(rxrpc_skb_put_oob, "PUT oob ") \
EM(rxrpc_skb_put_old_response, "PUT old-resp ") \
EM(rxrpc_skb_put_purge, "PUT purge ") \
EM(rxrpc_skb_put_purge_oob, "PUT purge-oob") \
EM(rxrpc_skb_put_response, "PUT response ") \
@@ -347,7 +348,7 @@
EM(rxrpc_call_see_release, "SEE release ") \
EM(rxrpc_call_see_userid_exists, "SEE u-exists") \
EM(rxrpc_call_see_waiting_call, "SEE q-conn ") \
E_(rxrpc_call_see_zap, "SEE zap ")
E_(rxrpc_call_see_still_live, "SEE !still-l")
#define rxrpc_txqueue_traces \
EM(rxrpc_txqueue_await_reply, "AWR") \
@@ -520,6 +521,7 @@
#define rxrpc_req_ack_traces \
EM(rxrpc_reqack_ack_lost, "ACK-LOST ") \
EM(rxrpc_reqack_app_stall, "APP-STALL ") \
EM(rxrpc_reqack_jumbo_win, "JUMBO-WIN ") \
EM(rxrpc_reqack_more_rtt, "MORE-RTT ") \
EM(rxrpc_reqack_no_srv_last, "NO-SRVLAST") \
EM(rxrpc_reqack_old_rtt, "OLD-RTT ") \

View File

@@ -2130,6 +2130,7 @@ batadv_bla_claim_dump_entry(struct sk_buff *msg, u32 portid,
struct batadv_bla_claim *claim)
{
const u8 *primary_addr = primary_if->net_dev->dev_addr;
struct batadv_bla_backbone_gw *backbone_gw;
u16 backbone_crc;
bool is_own;
void *hdr;
@@ -2145,32 +2146,35 @@ batadv_bla_claim_dump_entry(struct sk_buff *msg, u32 portid,
genl_dump_check_consistent(cb, hdr);
is_own = batadv_compare_eth(claim->backbone_gw->orig,
primary_addr);
backbone_gw = batadv_bla_claim_get_backbone_gw(claim);
spin_lock_bh(&claim->backbone_gw->crc_lock);
backbone_crc = claim->backbone_gw->crc;
spin_unlock_bh(&claim->backbone_gw->crc_lock);
is_own = batadv_compare_eth(backbone_gw->orig, primary_addr);
spin_lock_bh(&backbone_gw->crc_lock);
backbone_crc = backbone_gw->crc;
spin_unlock_bh(&backbone_gw->crc_lock);
if (is_own)
if (nla_put_flag(msg, BATADV_ATTR_BLA_OWN)) {
genlmsg_cancel(msg, hdr);
goto out;
goto put_backbone_gw;
}
if (nla_put(msg, BATADV_ATTR_BLA_ADDRESS, ETH_ALEN, claim->addr) ||
nla_put_u16(msg, BATADV_ATTR_BLA_VID, claim->vid) ||
nla_put(msg, BATADV_ATTR_BLA_BACKBONE, ETH_ALEN,
claim->backbone_gw->orig) ||
backbone_gw->orig) ||
nla_put_u16(msg, BATADV_ATTR_BLA_CRC,
backbone_crc)) {
genlmsg_cancel(msg, hdr);
goto out;
goto put_backbone_gw;
}
genlmsg_end(msg, hdr);
ret = 0;
put_backbone_gw:
batadv_backbone_gw_put(backbone_gw);
out:
return ret;
}
@@ -2448,6 +2452,7 @@ out:
bool batadv_bla_check_claim(struct batadv_priv *bat_priv,
u8 *addr, unsigned short vid)
{
struct batadv_bla_backbone_gw *backbone_gw;
struct batadv_bla_claim search_claim;
struct batadv_bla_claim *claim = NULL;
struct batadv_hard_iface *primary_if = NULL;
@@ -2470,9 +2475,13 @@ bool batadv_bla_check_claim(struct batadv_priv *bat_priv,
* return false.
*/
if (claim) {
if (!batadv_compare_eth(claim->backbone_gw->orig,
backbone_gw = batadv_bla_claim_get_backbone_gw(claim);
if (!batadv_compare_eth(backbone_gw->orig,
primary_if->net_dev->dev_addr))
ret = false;
batadv_backbone_gw_put(backbone_gw);
batadv_claim_put(claim);
}

View File

@@ -798,8 +798,8 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node,
{
u16 num_vlan = 0;
u16 num_entries = 0;
u16 change_offset;
u16 tvlv_len;
u16 tvlv_len = 0;
unsigned int change_offset;
struct batadv_tvlv_tt_vlan_data *tt_vlan;
struct batadv_orig_node_vlan *vlan;
u8 *tt_change_ptr;
@@ -816,6 +816,11 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node,
if (*tt_len < 0)
*tt_len = batadv_tt_len(num_entries);
if (change_offset > U16_MAX || *tt_len > U16_MAX - change_offset) {
*tt_len = 0;
goto out;
}
tvlv_len = *tt_len;
tvlv_len += change_offset;

View File

@@ -597,6 +597,9 @@ static void br_fdb_delete_locals_per_vlan_port(struct net_bridge *br,
dev = br->dev;
}
if (!vg)
return;
list_for_each_entry(v, &vg->vlan_list, vlist)
br_fdb_find_delete_local(br, p, dev->dev_addr, v->vid);
}
@@ -630,6 +633,9 @@ static int br_fdb_insert_locals_per_vlan_port(struct net_bridge *br,
dev = br->dev;
}
if (!vg)
return 0;
list_for_each_entry(v, &vg->vlan_list, vlist) {
if (!br_vlan_should_use(v))
continue;

View File

@@ -117,7 +117,7 @@ int __net_mp_open_rxq(struct net_device *dev, unsigned int rxq_idx,
struct netdev_rx_queue *rxq;
int ret;
if (!netdev_need_ops_lock(dev))
if (!qops)
return -EOPNOTSUPP;
if (rxq_idx >= dev->real_num_rx_queues) {

View File

@@ -3894,28 +3894,42 @@ out_unregister:
goto out;
}
static struct net *rtnl_get_peer_net(const struct rtnl_link_ops *ops,
static struct net *rtnl_get_peer_net(struct sk_buff *skb,
const struct rtnl_link_ops *ops,
struct nlattr *tbp[],
struct nlattr *data[],
struct netlink_ext_ack *extack)
{
struct nlattr *tb[IFLA_MAX + 1];
struct nlattr *tb[IFLA_MAX + 1], **attrs;
struct net *net;
int err;
if (!data || !data[ops->peer_type])
return rtnl_link_get_net_ifla(tbp);
err = rtnl_nla_parse_ifinfomsg(tb, data[ops->peer_type], extack);
if (err < 0)
return ERR_PTR(err);
if (ops->validate) {
err = ops->validate(tb, NULL, extack);
if (!data || !data[ops->peer_type]) {
attrs = tbp;
} else {
err = rtnl_nla_parse_ifinfomsg(tb, data[ops->peer_type], extack);
if (err < 0)
return ERR_PTR(err);
if (ops->validate) {
err = ops->validate(tb, NULL, extack);
if (err < 0)
return ERR_PTR(err);
}
attrs = tb;
}
return rtnl_link_get_net_ifla(tb);
net = rtnl_link_get_net_ifla(attrs);
if (IS_ERR_OR_NULL(net))
return net;
if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) {
put_net(net);
return ERR_PTR(-EPERM);
}
return net;
}
static int __rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
@@ -4054,7 +4068,7 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
}
if (ops->peer_type) {
peer_net = rtnl_get_peer_net(ops, tb, data, extack);
peer_net = rtnl_get_peer_net(skb, ops, tb, data, extack);
if (IS_ERR(peer_net)) {
ret = PTR_ERR(peer_net);
goto put_ops;

View File

@@ -1083,10 +1083,7 @@ static int skb_pp_frag_ref(struct sk_buff *skb)
static void skb_kfree_head(void *head, unsigned int end_offset)
{
if (end_offset == SKB_SMALL_HEAD_HEADROOM)
kmem_cache_free(net_hotdata.skb_small_head_cache, head);
else
kfree(head);
kfree(head);
}
static void skb_free_head(struct sk_buff *skb)

View File

@@ -1327,7 +1327,7 @@ void devlink_fmsg_dump_skb(struct devlink_fmsg *fmsg, const struct sk_buff *skb)
if (sk) {
devlink_fmsg_pair_nest_start(fmsg, "sk");
devlink_fmsg_obj_nest_start(fmsg);
devlink_fmsg_put(fmsg, "family", sk->sk_type);
devlink_fmsg_put(fmsg, "family", sk->sk_family);
devlink_fmsg_put(fmsg, "type", sk->sk_type);
devlink_fmsg_put(fmsg, "proto", sk->sk_protocol);
devlink_fmsg_obj_nest_end(fmsg);

View File

@@ -1346,6 +1346,13 @@ bool icmp_build_probe(struct sk_buff *skb, struct icmphdr *icmphdr)
if (iio->ident.addr.ctype3_hdr.addrlen != sizeof(struct in6_addr))
goto send_mal_query;
dev = ipv6_stub->ipv6_dev_find(net, &iio->ident.addr.ip_addr.ipv6_addr, dev);
/*
* If IPv6 identifier lookup is unavailable, silently
* discard the request instead of misreporting NO_IF.
*/
if (IS_ERR(dev))
return false;
dev_hold(dev);
break;
#endif

View File

@@ -902,8 +902,7 @@ static int nla_put_nh_group(struct sk_buff *skb, struct nexthop *nh,
goto nla_put_failure;
if (op_flags & NHA_OP_FLAG_DUMP_STATS &&
(nla_put_u32(skb, NHA_HW_STATS_ENABLE, nhg->hw_stats) ||
nla_put_nh_group_stats(skb, nh, op_flags)))
nla_put_nh_group_stats(skb, nh, op_flags))
goto nla_put_failure;
return 0;
@@ -1004,16 +1003,32 @@ static size_t nh_nlmsg_size_grp_res(struct nh_group *nhg)
nla_total_size_64bit(8);/* NHA_RES_GROUP_UNBALANCED_TIME */
}
static size_t nh_nlmsg_size_grp(struct nexthop *nh)
static size_t nh_nlmsg_size_grp(struct nexthop *nh, u32 op_flags)
{
struct nh_group *nhg = rtnl_dereference(nh->nh_grp);
size_t sz = sizeof(struct nexthop_grp) * nhg->num_nh;
size_t tot = nla_total_size(sz) +
nla_total_size(2); /* NHA_GROUP_TYPE */
nla_total_size(2) + /* NHA_GROUP_TYPE */
nla_total_size(0); /* NHA_FDB */
if (nhg->resilient)
tot += nh_nlmsg_size_grp_res(nhg);
if (op_flags & NHA_OP_FLAG_DUMP_STATS) {
tot += nla_total_size(0) + /* NHA_GROUP_STATS */
nla_total_size(4); /* NHA_HW_STATS_ENABLE */
tot += nhg->num_nh *
(nla_total_size(0) + /* NHA_GROUP_STATS_ENTRY */
nla_total_size(4) + /* NHA_GROUP_STATS_ENTRY_ID */
nla_total_size_64bit(8)); /* NHA_GROUP_STATS_ENTRY_PACKETS */
if (op_flags & NHA_OP_FLAG_DUMP_HW_STATS) {
tot += nhg->num_nh *
nla_total_size_64bit(8); /* NHA_GROUP_STATS_ENTRY_PACKETS_HW */
tot += nla_total_size(4); /* NHA_HW_STATS_USED */
}
}
return tot;
}
@@ -1048,14 +1063,14 @@ static size_t nh_nlmsg_size_single(struct nexthop *nh)
return sz;
}
static size_t nh_nlmsg_size(struct nexthop *nh)
static size_t nh_nlmsg_size(struct nexthop *nh, u32 op_flags)
{
size_t sz = NLMSG_ALIGN(sizeof(struct nhmsg));
sz += nla_total_size(4); /* NHA_ID */
if (nh->is_group)
sz += nh_nlmsg_size_grp(nh) +
sz += nh_nlmsg_size_grp(nh, op_flags) +
nla_total_size(4) + /* NHA_OP_FLAGS */
0;
else
@@ -1071,7 +1086,7 @@ static void nexthop_notify(int event, struct nexthop *nh, struct nl_info *info)
struct sk_buff *skb;
int err = -ENOBUFS;
skb = nlmsg_new(nh_nlmsg_size(nh), gfp_any());
skb = nlmsg_new(nh_nlmsg_size(nh, 0), gfp_any());
if (!skb)
goto errout;
@@ -3377,15 +3392,15 @@ static int rtm_get_nexthop(struct sk_buff *in_skb, struct nlmsghdr *nlh,
if (err)
return err;
err = -ENOBUFS;
skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
if (!skb)
goto out;
err = -ENOENT;
nh = nexthop_find_by_id(net, id);
if (!nh)
goto errout_free;
goto out;
err = -ENOBUFS;
skb = nlmsg_new(nh_nlmsg_size(nh, op_flags), GFP_KERNEL);
if (!skb)
goto out;
err = nh_fill_node(skb, nh, RTM_NEWNEXTHOP, NETLINK_CB(in_skb).portid,
nlh->nlmsg_seq, 0, op_flags);

View File

@@ -50,6 +50,7 @@ int xfrm4_transport_finish(struct sk_buff *skb, int async)
{
struct xfrm_offload *xo = xfrm_offload(skb);
struct iphdr *iph = ip_hdr(skb);
struct net_device *dev = skb->dev;
iph->protocol = XFRM_MODE_SKB_CB(skb)->protocol;
@@ -73,8 +74,10 @@ int xfrm4_transport_finish(struct sk_buff *skb, int async)
}
NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING,
dev_net(skb->dev), NULL, skb, skb->dev, NULL,
dev_net(dev), NULL, skb, dev, NULL,
xfrm4_rcv_encap_finish);
if (async)
dev_put(dev);
return 0;
}

View File

@@ -710,7 +710,9 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
struct ioam6_schema *sc,
unsigned int sclen, bool is_input)
{
struct net_device *dev = skb_dst_dev(skb);
/* Note: skb_dst_dev_rcu() can't be NULL at this point. */
struct net_device *dev = skb_dst_dev_rcu(skb);
struct inet6_dev *i_skb_dev, *idev;
struct timespec64 ts;
ktime_t tstamp;
u64 raw64;
@@ -721,13 +723,16 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
data = trace->data + trace->remlen * 4 - trace->nodelen * 4 - sclen * 4;
i_skb_dev = skb->dev ? __in6_dev_get(skb->dev) : NULL;
idev = __in6_dev_get(dev);
/* hop_lim and node_id */
if (trace->type.bit0) {
byte = ipv6_hdr(skb)->hop_limit;
if (is_input)
byte--;
raw32 = dev_net(dev)->ipv6.sysctl.ioam6_id;
raw32 = READ_ONCE(dev_net(dev)->ipv6.sysctl.ioam6_id);
*(__be32 *)data = cpu_to_be32((byte << 24) | raw32);
data += sizeof(__be32);
@@ -735,18 +740,18 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
/* ingress_if_id and egress_if_id */
if (trace->type.bit1) {
if (!skb->dev)
if (!i_skb_dev)
raw16 = IOAM6_U16_UNAVAILABLE;
else
raw16 = (__force u16)READ_ONCE(__in6_dev_get(skb->dev)->cnf.ioam6_id);
raw16 = (__force u16)READ_ONCE(i_skb_dev->cnf.ioam6_id);
*(__be16 *)data = cpu_to_be16(raw16);
data += sizeof(__be16);
if (dev->flags & IFF_LOOPBACK)
if ((dev->flags & IFF_LOOPBACK) || !idev)
raw16 = IOAM6_U16_UNAVAILABLE;
else
raw16 = (__force u16)READ_ONCE(__in6_dev_get(dev)->cnf.ioam6_id);
raw16 = (__force u16)READ_ONCE(idev->cnf.ioam6_id);
*(__be16 *)data = cpu_to_be16(raw16);
data += sizeof(__be16);
@@ -798,12 +803,16 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
struct Qdisc *qdisc;
__u32 qlen, backlog;
if (dev->flags & IFF_LOOPBACK) {
if (dev->flags & IFF_LOOPBACK ||
skb_get_queue_mapping(skb) >= dev->num_tx_queues) {
*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
} else {
queue = skb_get_tx_queue(dev, skb);
qdisc = rcu_dereference(queue->qdisc);
spin_lock_bh(qdisc_lock(qdisc));
qdisc_qstats_qlen_backlog(qdisc, &qlen, &backlog);
spin_unlock_bh(qdisc_lock(qdisc));
*(__be32 *)data = cpu_to_be32(backlog);
}
@@ -822,7 +831,7 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
if (is_input)
byte--;
raw64 = dev_net(dev)->ipv6.sysctl.ioam6_id_wide;
raw64 = READ_ONCE(dev_net(dev)->ipv6.sysctl.ioam6_id_wide);
*(__be64 *)data = cpu_to_be64(((u64)byte << 56) | raw64);
data += sizeof(__be64);
@@ -830,18 +839,18 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
/* ingress_if_id and egress_if_id (wide) */
if (trace->type.bit9) {
if (!skb->dev)
if (!i_skb_dev)
raw32 = IOAM6_U32_UNAVAILABLE;
else
raw32 = READ_ONCE(__in6_dev_get(skb->dev)->cnf.ioam6_id_wide);
raw32 = READ_ONCE(i_skb_dev->cnf.ioam6_id_wide);
*(__be32 *)data = cpu_to_be32(raw32);
data += sizeof(__be32);
if (dev->flags & IFF_LOOPBACK)
if ((dev->flags & IFF_LOOPBACK) || !idev)
raw32 = IOAM6_U32_UNAVAILABLE;
else
raw32 = READ_ONCE(__in6_dev_get(dev)->cnf.ioam6_id_wide);
raw32 = READ_ONCE(idev->cnf.ioam6_id_wide);
*(__be32 *)data = cpu_to_be32(raw32);
data += sizeof(__be32);

View File

@@ -22,8 +22,7 @@ eui64_mt6(const struct sk_buff *skb, struct xt_action_param *par)
unsigned char eui64[8];
if (!(skb_mac_header(skb) >= skb->head &&
skb_mac_header(skb) + ETH_HLEN <= skb->data) &&
par->fragoff != 0) {
skb_mac_header(skb) + ETH_HLEN <= skb->data)) {
par->hotdrop = true;
return false;
}

View File

@@ -48,7 +48,8 @@ static size_t seg6_lwt_headroom(struct seg6_iptunnel_encap *tuninfo)
}
struct seg6_lwt {
struct dst_cache cache;
struct dst_cache cache_input;
struct dst_cache cache_output;
struct seg6_iptunnel_encap tuninfo[];
};
@@ -488,7 +489,7 @@ static int seg6_input_core(struct net *net, struct sock *sk,
slwt = seg6_lwt_lwtunnel(lwtst);
local_bh_disable();
dst = dst_cache_get(&slwt->cache);
dst = dst_cache_get(&slwt->cache_input);
local_bh_enable();
err = seg6_do_srh(skb, dst);
@@ -504,7 +505,7 @@ static int seg6_input_core(struct net *net, struct sock *sk,
/* cache only if we don't create a dst reference loop */
if (!dst->error && lwtst != dst->lwtstate) {
local_bh_disable();
dst_cache_set_ip6(&slwt->cache, dst,
dst_cache_set_ip6(&slwt->cache_input, dst,
&ipv6_hdr(skb)->saddr);
local_bh_enable();
}
@@ -564,7 +565,7 @@ static int seg6_output_core(struct net *net, struct sock *sk,
slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate);
local_bh_disable();
dst = dst_cache_get(&slwt->cache);
dst = dst_cache_get(&slwt->cache_output);
local_bh_enable();
err = seg6_do_srh(skb, dst);
@@ -591,7 +592,7 @@ static int seg6_output_core(struct net *net, struct sock *sk,
/* cache only if we don't create a dst reference loop */
if (orig_dst->lwtstate != dst->lwtstate) {
local_bh_disable();
dst_cache_set_ip6(&slwt->cache, dst, &fl6.saddr);
dst_cache_set_ip6(&slwt->cache_output, dst, &fl6.saddr);
local_bh_enable();
}
@@ -701,11 +702,13 @@ static int seg6_build_state(struct net *net, struct nlattr *nla,
slwt = seg6_lwt_lwtunnel(newts);
err = dst_cache_init(&slwt->cache, GFP_ATOMIC);
if (err) {
kfree(newts);
return err;
}
err = dst_cache_init(&slwt->cache_input, GFP_ATOMIC);
if (err)
goto err_free_newts;
err = dst_cache_init(&slwt->cache_output, GFP_ATOMIC);
if (err)
goto err_destroy_input;
memcpy(&slwt->tuninfo, tuninfo, tuninfo_len);
@@ -720,11 +723,20 @@ static int seg6_build_state(struct net *net, struct nlattr *nla,
*ts = newts;
return 0;
err_destroy_input:
dst_cache_destroy(&slwt->cache_input);
err_free_newts:
kfree(newts);
return err;
}
static void seg6_destroy_state(struct lwtunnel_state *lwt)
{
dst_cache_destroy(&seg6_lwt_lwtunnel(lwt)->cache);
struct seg6_lwt *slwt = seg6_lwt_lwtunnel(lwt);
dst_cache_destroy(&slwt->cache_input);
dst_cache_destroy(&slwt->cache_output);
}
static int seg6_fill_encap_info(struct sk_buff *skb,

View File

@@ -43,6 +43,7 @@ static int xfrm6_transport_finish2(struct net *net, struct sock *sk,
int xfrm6_transport_finish(struct sk_buff *skb, int async)
{
struct xfrm_offload *xo = xfrm_offload(skb);
struct net_device *dev = skb->dev;
int nhlen = -skb_network_offset(skb);
skb_network_header(skb)[IP6CB(skb)->nhoff] =
@@ -68,8 +69,10 @@ int xfrm6_transport_finish(struct sk_buff *skb, int async)
}
NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING,
dev_net(skb->dev), NULL, skb, skb->dev, NULL,
dev_net(dev), NULL, skb, dev, NULL,
xfrm6_transport_finish2);
if (async)
dev_put(dev);
return 0;
}

View File

@@ -757,6 +757,22 @@ static unsigned int pfkey_sockaddr_fill(const xfrm_address_t *xaddr, __be16 port
return 0;
}
static unsigned int pfkey_sockaddr_fill_zero_tail(const xfrm_address_t *xaddr,
__be16 port,
struct sockaddr *sa,
unsigned short family)
{
unsigned int prefixlen;
int sockaddr_len = pfkey_sockaddr_len(family);
int sockaddr_size = pfkey_sockaddr_size(family);
prefixlen = pfkey_sockaddr_fill(xaddr, port, sa, family);
if (sockaddr_size > sockaddr_len)
memset((u8 *)sa + sockaddr_len, 0, sockaddr_size - sockaddr_len);
return prefixlen;
}
static struct sk_buff *__pfkey_xfrm_state2msg(const struct xfrm_state *x,
int add_keys, int hsc)
{
@@ -3206,9 +3222,9 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
addr->sadb_address_proto = 0;
addr->sadb_address_reserved = 0;
addr->sadb_address_prefixlen =
pfkey_sockaddr_fill(&x->props.saddr, 0,
(struct sockaddr *) (addr + 1),
x->props.family);
pfkey_sockaddr_fill_zero_tail(&x->props.saddr, 0,
(struct sockaddr *)(addr + 1),
x->props.family);
if (!addr->sadb_address_prefixlen)
BUG();
@@ -3221,9 +3237,9 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
addr->sadb_address_proto = 0;
addr->sadb_address_reserved = 0;
addr->sadb_address_prefixlen =
pfkey_sockaddr_fill(&x->id.daddr, 0,
(struct sockaddr *) (addr + 1),
x->props.family);
pfkey_sockaddr_fill_zero_tail(&x->id.daddr, 0,
(struct sockaddr *)(addr + 1),
x->props.family);
if (!addr->sadb_address_prefixlen)
BUG();
@@ -3421,9 +3437,9 @@ static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr,
addr->sadb_address_proto = 0;
addr->sadb_address_reserved = 0;
addr->sadb_address_prefixlen =
pfkey_sockaddr_fill(&x->props.saddr, 0,
(struct sockaddr *) (addr + 1),
x->props.family);
pfkey_sockaddr_fill_zero_tail(&x->props.saddr, 0,
(struct sockaddr *)(addr + 1),
x->props.family);
if (!addr->sadb_address_prefixlen)
BUG();
@@ -3443,9 +3459,9 @@ static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr,
addr->sadb_address_proto = 0;
addr->sadb_address_reserved = 0;
addr->sadb_address_prefixlen =
pfkey_sockaddr_fill(ipaddr, 0,
(struct sockaddr *) (addr + 1),
x->props.family);
pfkey_sockaddr_fill_zero_tail(ipaddr, 0,
(struct sockaddr *)(addr + 1),
x->props.family);
if (!addr->sadb_address_prefixlen)
BUG();
@@ -3474,15 +3490,15 @@ static int set_sadb_address(struct sk_buff *skb, int sasize, int type,
switch (type) {
case SADB_EXT_ADDRESS_SRC:
addr->sadb_address_prefixlen = sel->prefixlen_s;
pfkey_sockaddr_fill(&sel->saddr, 0,
(struct sockaddr *)(addr + 1),
sel->family);
pfkey_sockaddr_fill_zero_tail(&sel->saddr, 0,
(struct sockaddr *)(addr + 1),
sel->family);
break;
case SADB_EXT_ADDRESS_DST:
addr->sadb_address_prefixlen = sel->prefixlen_d;
pfkey_sockaddr_fill(&sel->daddr, 0,
(struct sockaddr *)(addr + 1),
sel->family);
pfkey_sockaddr_fill_zero_tail(&sel->daddr, 0,
(struct sockaddr *)(addr + 1),
sel->family);
break;
default:
return -EINVAL;

View File

@@ -1290,6 +1290,11 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, uns
uh->source = inet->inet_sport;
uh->dest = inet->inet_dport;
udp_len = uhlen + session->hdr_len + data_len;
if (udp_len > U16_MAX) {
kfree_skb(skb);
ret = NET_XMIT_DROP;
goto out_unlock;
}
uh->len = htons(udp_len);
/* Calculate UDP checksum if configured to do so */

View File

@@ -720,7 +720,7 @@ static void __mptcp_pm_release_addr_entry(struct mptcp_pm_addr_entry *entry)
static int mptcp_pm_nl_append_new_local_addr(struct pm_nl_pernet *pernet,
struct mptcp_pm_addr_entry *entry,
bool needs_id, bool replace)
bool replace)
{
struct mptcp_pm_addr_entry *cur, *del_entry = NULL;
int ret = -EINVAL;
@@ -779,7 +779,7 @@ static int mptcp_pm_nl_append_new_local_addr(struct pm_nl_pernet *pernet,
}
}
if (!entry->addr.id && needs_id) {
if (!entry->addr.id) {
find_next:
entry->addr.id = find_next_zero_bit(pernet->id_bitmap,
MPTCP_PM_MAX_ADDR_ID + 1,
@@ -790,7 +790,7 @@ find_next:
}
}
if (!entry->addr.id && needs_id)
if (!entry->addr.id)
goto out;
__set_bit(entry->addr.id, pernet->id_bitmap);
@@ -923,7 +923,7 @@ int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk,
return -ENOMEM;
entry->addr.port = 0;
ret = mptcp_pm_nl_append_new_local_addr(pernet, entry, true, false);
ret = mptcp_pm_nl_append_new_local_addr(pernet, entry, false);
if (ret < 0)
kfree(entry);
@@ -977,18 +977,6 @@ next:
return 0;
}
static bool mptcp_pm_has_addr_attr_id(const struct nlattr *attr,
struct genl_info *info)
{
struct nlattr *tb[MPTCP_PM_ADDR_ATTR_MAX + 1];
if (!nla_parse_nested_deprecated(tb, MPTCP_PM_ADDR_ATTR_MAX, attr,
mptcp_pm_address_nl_policy, info->extack) &&
tb[MPTCP_PM_ADDR_ATTR_ID])
return true;
return false;
}
/* Add an MPTCP endpoint */
int mptcp_pm_nl_add_addr_doit(struct sk_buff *skb, struct genl_info *info)
{
@@ -1037,9 +1025,7 @@ int mptcp_pm_nl_add_addr_doit(struct sk_buff *skb, struct genl_info *info)
goto out_free;
}
}
ret = mptcp_pm_nl_append_new_local_addr(pernet, entry,
!mptcp_pm_has_addr_attr_id(attr, info),
true);
ret = mptcp_pm_nl_append_new_local_addr(pernet, entry, true);
if (ret < 0) {
GENL_SET_ERR_MSG_FMT(info, "too many addresses or duplicate one: %d", ret);
goto out_free;

View File

@@ -4660,6 +4660,8 @@ int __init mptcp_proto_v6_init(void)
{
int err;
mptcp_subflow_v6_init();
mptcp_v6_prot = mptcp_prot;
strscpy(mptcp_v6_prot.name, "MPTCPv6", sizeof(mptcp_v6_prot.name));
mptcp_v6_prot.slab = NULL;

View File

@@ -875,6 +875,7 @@ static inline void mptcp_subflow_tcp_fallback(struct sock *sk,
void __init mptcp_proto_init(void);
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
int __init mptcp_proto_v6_init(void);
void __init mptcp_subflow_v6_init(void);
#endif
struct sock *mptcp_sk_clone_init(const struct sock *sk,

View File

@@ -2165,7 +2165,15 @@ void __init mptcp_subflow_init(void)
tcp_prot_override.psock_update_sk_prot = NULL;
#endif
mptcp_diag_subflow_init(&subflow_ulp_ops);
if (tcp_register_ulp(&subflow_ulp_ops) != 0)
panic("MPTCP: failed to register subflows to ULP\n");
}
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
void __init mptcp_subflow_v6_init(void)
{
/* In struct mptcp_subflow_request_sock, we assume the TCP request sock
* structures for v4 and v6 have the same size. It should not changed in
* the future but better to make sure to be warned if it is no longer
@@ -2204,10 +2212,5 @@ void __init mptcp_subflow_init(void)
/* Disable sockmap processing for subflows */
tcpv6_prot_override.psock_update_sk_prot = NULL;
#endif
#endif
mptcp_diag_subflow_init(&subflow_ulp_ops);
if (tcp_register_ulp(&subflow_ulp_ops) != 0)
panic("MPTCP: failed to register subflows to ULP\n");
}
#endif

View File

@@ -1452,7 +1452,6 @@ ip_vs_add_service(struct netns_ipvs *ipvs, struct ip_vs_service_user_kern *u,
ret = ip_vs_bind_scheduler(svc, sched);
if (ret)
goto out_err;
sched = NULL;
}
ret = ip_vs_start_estimator(ipvs, &svc->stats);

View File

@@ -361,10 +361,10 @@ static void
__nfulnl_send(struct nfulnl_instance *inst)
{
if (inst->qlen > 1) {
struct nlmsghdr *nlh = nlmsg_put(inst->skb, 0, 0,
NLMSG_DONE,
sizeof(struct nfgenmsg),
0);
struct nlmsghdr *nlh = nfnl_msg_put(inst->skb, 0, 0,
NLMSG_DONE, 0,
AF_UNSPEC, NFNETLINK_V0,
htons(inst->group_num));
if (WARN_ONCE(!nlh, "bad nlskb size: %u, tailroom %d\n",
inst->skb->len, skb_tailroom(inst->skb))) {
kfree_skb(inst->skb);

View File

@@ -49,8 +49,8 @@
#endif
#define NFQNL_QMAX_DEFAULT 1024
#define NFQNL_HASH_MIN 1024
#define NFQNL_HASH_MAX 1048576
#define NFQNL_HASH_MIN 8
#define NFQNL_HASH_MAX 32768
/* We're using struct nlattr which has 16bit nla_len. Note that nla_len
* includes the header length. Thus, the maximum packet length that we
@@ -60,29 +60,10 @@
*/
#define NFQNL_MAX_COPY_RANGE (0xffff - NLA_HDRLEN)
/* Composite key for packet lookup: (net, queue_num, packet_id) */
struct nfqnl_packet_key {
possible_net_t net;
u32 packet_id;
u16 queue_num;
} __aligned(sizeof(u32)); /* jhash2 requires 32-bit alignment */
/* Global rhashtable - one for entire system, all netns */
static struct rhashtable nfqnl_packet_map __read_mostly;
/* Helper to initialize composite key */
static inline void nfqnl_init_key(struct nfqnl_packet_key *key,
struct net *net, u32 packet_id, u16 queue_num)
{
memset(key, 0, sizeof(*key));
write_pnet(&key->net, net);
key->packet_id = packet_id;
key->queue_num = queue_num;
}
struct nfqnl_instance {
struct hlist_node hlist; /* global list of queues */
struct rcu_head rcu;
struct rhashtable nfqnl_packet_map;
struct rcu_work rwork;
u32 peer_portid;
unsigned int queue_maxlen;
@@ -106,6 +87,7 @@ struct nfqnl_instance {
typedef int (*nfqnl_cmpfn)(struct nf_queue_entry *, unsigned long);
static struct workqueue_struct *nfq_cleanup_wq __read_mostly;
static unsigned int nfnl_queue_net_id __read_mostly;
#define INSTANCE_BUCKETS 16
@@ -124,34 +106,10 @@ static inline u_int8_t instance_hashfn(u_int16_t queue_num)
return ((queue_num >> 8) ^ queue_num) % INSTANCE_BUCKETS;
}
/* Extract composite key from nf_queue_entry for hashing */
static u32 nfqnl_packet_obj_hashfn(const void *data, u32 len, u32 seed)
{
const struct nf_queue_entry *entry = data;
struct nfqnl_packet_key key;
nfqnl_init_key(&key, entry->state.net, entry->id, entry->queue_num);
return jhash2((u32 *)&key, sizeof(key) / sizeof(u32), seed);
}
/* Compare stack-allocated key against entry */
static int nfqnl_packet_obj_cmpfn(struct rhashtable_compare_arg *arg,
const void *obj)
{
const struct nfqnl_packet_key *key = arg->key;
const struct nf_queue_entry *entry = obj;
return !net_eq(entry->state.net, read_pnet(&key->net)) ||
entry->queue_num != key->queue_num ||
entry->id != key->packet_id;
}
static const struct rhashtable_params nfqnl_rhashtable_params = {
.head_offset = offsetof(struct nf_queue_entry, hash_node),
.key_len = sizeof(struct nfqnl_packet_key),
.obj_hashfn = nfqnl_packet_obj_hashfn,
.obj_cmpfn = nfqnl_packet_obj_cmpfn,
.key_offset = offsetof(struct nf_queue_entry, id),
.key_len = sizeof(u32),
.automatic_shrinking = true,
.min_size = NFQNL_HASH_MIN,
.max_size = NFQNL_HASH_MAX,
@@ -190,6 +148,10 @@ instance_create(struct nfnl_queue_net *q, u_int16_t queue_num, u32 portid)
spin_lock_init(&inst->lock);
INIT_LIST_HEAD(&inst->queue_list);
err = rhashtable_init(&inst->nfqnl_packet_map, &nfqnl_rhashtable_params);
if (err < 0)
goto out_free;
spin_lock(&q->instances_lock);
if (instance_lookup(q, queue_num)) {
err = -EEXIST;
@@ -210,6 +172,8 @@ instance_create(struct nfnl_queue_net *q, u_int16_t queue_num, u32 portid)
out_unlock:
spin_unlock(&q->instances_lock);
rhashtable_destroy(&inst->nfqnl_packet_map);
out_free:
kfree(inst);
return ERR_PTR(err);
}
@@ -217,15 +181,18 @@ out_unlock:
static void nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn,
unsigned long data);
static void
instance_destroy_rcu(struct rcu_head *head)
static void instance_destroy_work(struct work_struct *work)
{
struct nfqnl_instance *inst = container_of(head, struct nfqnl_instance,
rcu);
struct nfqnl_instance *inst;
inst = container_of(to_rcu_work(work), struct nfqnl_instance,
rwork);
rcu_read_lock();
nfqnl_flush(inst, NULL, 0);
rcu_read_unlock();
rhashtable_destroy(&inst->nfqnl_packet_map);
kfree(inst);
module_put(THIS_MODULE);
}
@@ -234,7 +201,9 @@ static void
__instance_destroy(struct nfqnl_instance *inst)
{
hlist_del_rcu(&inst->hlist);
call_rcu(&inst->rcu, instance_destroy_rcu);
INIT_RCU_WORK(&inst->rwork, instance_destroy_work);
queue_rcu_work(nfq_cleanup_wq, &inst->rwork);
}
static void
@@ -250,9 +219,7 @@ __enqueue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry)
{
int err;
entry->queue_num = queue->queue_num;
err = rhashtable_insert_fast(&nfqnl_packet_map, &entry->hash_node,
err = rhashtable_insert_fast(&queue->nfqnl_packet_map, &entry->hash_node,
nfqnl_rhashtable_params);
if (unlikely(err))
return err;
@@ -266,23 +233,19 @@ __enqueue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry)
static void
__dequeue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry)
{
rhashtable_remove_fast(&nfqnl_packet_map, &entry->hash_node,
rhashtable_remove_fast(&queue->nfqnl_packet_map, &entry->hash_node,
nfqnl_rhashtable_params);
list_del(&entry->list);
queue->queue_total--;
}
static struct nf_queue_entry *
find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id,
struct net *net)
find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id)
{
struct nfqnl_packet_key key;
struct nf_queue_entry *entry;
nfqnl_init_key(&key, net, id, queue->queue_num);
spin_lock_bh(&queue->lock);
entry = rhashtable_lookup_fast(&nfqnl_packet_map, &key,
entry = rhashtable_lookup_fast(&queue->nfqnl_packet_map, &id,
nfqnl_rhashtable_params);
if (entry)
@@ -1531,7 +1494,7 @@ static int nfqnl_recv_verdict(struct sk_buff *skb, const struct nfnl_info *info,
verdict = ntohl(vhdr->verdict);
entry = find_dequeue_entry(queue, ntohl(vhdr->id), info->net);
entry = find_dequeue_entry(queue, ntohl(vhdr->id));
if (entry == NULL)
return -ENOENT;
@@ -1880,40 +1843,38 @@ static int __init nfnetlink_queue_init(void)
{
int status;
status = rhashtable_init(&nfqnl_packet_map, &nfqnl_rhashtable_params);
if (status < 0)
return status;
nfq_cleanup_wq = alloc_ordered_workqueue("nfq_workqueue", 0);
if (!nfq_cleanup_wq)
return -ENOMEM;
status = register_pernet_subsys(&nfnl_queue_net_ops);
if (status < 0) {
pr_err("failed to register pernet ops\n");
goto cleanup_rhashtable;
}
if (status < 0)
goto cleanup_pernet_subsys;
netlink_register_notifier(&nfqnl_rtnl_notifier);
status = nfnetlink_subsys_register(&nfqnl_subsys);
if (status < 0) {
pr_err("failed to create netlink socket\n");
goto cleanup_netlink_notifier;
}
status = netlink_register_notifier(&nfqnl_rtnl_notifier);
if (status < 0)
goto cleanup_rtnl_notifier;
status = register_netdevice_notifier(&nfqnl_dev_notifier);
if (status < 0) {
pr_err("failed to register netdevice notifier\n");
goto cleanup_netlink_subsys;
}
if (status < 0)
goto cleanup_dev_notifier;
status = nfnetlink_subsys_register(&nfqnl_subsys);
if (status < 0)
goto cleanup_nfqnl_subsys;
nf_register_queue_handler(&nfqh);
return status;
cleanup_netlink_subsys:
nfnetlink_subsys_unregister(&nfqnl_subsys);
cleanup_netlink_notifier:
cleanup_nfqnl_subsys:
unregister_netdevice_notifier(&nfqnl_dev_notifier);
cleanup_dev_notifier:
netlink_unregister_notifier(&nfqnl_rtnl_notifier);
cleanup_rtnl_notifier:
unregister_pernet_subsys(&nfnl_queue_net_ops);
cleanup_rhashtable:
rhashtable_destroy(&nfqnl_packet_map);
cleanup_pernet_subsys:
destroy_workqueue(nfq_cleanup_wq);
return status;
}
@@ -1924,9 +1885,7 @@ static void __exit nfnetlink_queue_fini(void)
nfnetlink_subsys_unregister(&nfqnl_subsys);
netlink_unregister_notifier(&nfqnl_rtnl_notifier);
unregister_pernet_subsys(&nfnl_queue_net_ops);
rhashtable_destroy(&nfqnl_packet_map);
destroy_workqueue(nfq_cleanup_wq);
rcu_barrier(); /* Wait for completion of call_rcu()'s */
}

View File

@@ -1020,7 +1020,7 @@ static void nft_ct_timeout_obj_destroy(const struct nft_ctx *ctx,
nf_queue_nf_hook_drop(ctx->net);
nf_ct_untimeout(ctx->net, timeout);
nf_ct_netns_put(ctx->net, ctx->family);
kfree(priv->timeout);
kfree_rcu(priv->timeout, rcu);
}
static int nft_ct_timeout_obj_dump(struct sk_buff *skb,

View File

@@ -105,6 +105,28 @@ multiport_mt(const struct sk_buff *skb, struct xt_action_param *par)
return ports_match_v1(multiinfo, ntohs(pptr[0]), ntohs(pptr[1]));
}
static bool
multiport_valid_ranges(const struct xt_multiport_v1 *multiinfo)
{
unsigned int i;
for (i = 0; i < multiinfo->count; i++) {
if (!multiinfo->pflags[i])
continue;
if (++i >= multiinfo->count)
return false;
if (multiinfo->pflags[i])
return false;
if (multiinfo->ports[i - 1] > multiinfo->ports[i])
return false;
}
return true;
}
static inline bool
check(u_int16_t proto,
u_int8_t ip_invflags,
@@ -127,8 +149,10 @@ static int multiport_mt_check(const struct xt_mtchk_param *par)
const struct ipt_ip *ip = par->entryinfo;
const struct xt_multiport_v1 *multiinfo = par->matchinfo;
return check(ip->proto, ip->invflags, multiinfo->flags,
multiinfo->count) ? 0 : -EINVAL;
if (!check(ip->proto, ip->invflags, multiinfo->flags, multiinfo->count))
return -EINVAL;
return multiport_valid_ranges(multiinfo) ? 0 : -EINVAL;
}
static int multiport_mt6_check(const struct xt_mtchk_param *par)
@@ -136,8 +160,10 @@ static int multiport_mt6_check(const struct xt_mtchk_param *par)
const struct ip6t_ip6 *ip = par->entryinfo;
const struct xt_multiport_v1 *multiinfo = par->matchinfo;
return check(ip->proto, ip->invflags, multiinfo->flags,
multiinfo->count) ? 0 : -EINVAL;
if (!check(ip->proto, ip->invflags, multiinfo->flags, multiinfo->count))
return -EINVAL;
return multiport_valid_ranges(multiinfo) ? 0 : -EINVAL;
}
static struct xt_match multiport_mt_reg[] __read_mostly = {

View File

@@ -73,11 +73,14 @@ struct rfkill_int_event {
struct rfkill_event_ext ev;
};
/* Max rfkill events that can be "in-flight" for one data source */
#define MAX_RFKILL_EVENT 1000
struct rfkill_data {
struct list_head list;
struct list_head events;
struct mutex mtx;
wait_queue_head_t read_wait;
u32 event_count;
bool input_handler;
u8 max_size;
};
@@ -255,10 +258,12 @@ static void rfkill_global_led_trigger_unregister(void)
}
#endif /* CONFIG_RFKILL_LEDS */
static void rfkill_fill_event(struct rfkill_event_ext *ev,
struct rfkill *rfkill,
enum rfkill_operation op)
static int rfkill_fill_event(struct rfkill_int_event *int_ev,
struct rfkill *rfkill,
struct rfkill_data *data,
enum rfkill_operation op)
{
struct rfkill_event_ext *ev = &int_ev->ev;
unsigned long flags;
ev->idx = rfkill->idx;
@@ -271,6 +276,15 @@ static void rfkill_fill_event(struct rfkill_event_ext *ev,
RFKILL_BLOCK_SW_PREV));
ev->hard_block_reasons = rfkill->hard_block_reasons;
spin_unlock_irqrestore(&rfkill->lock, flags);
scoped_guard(mutex, &data->mtx) {
if (data->event_count++ > MAX_RFKILL_EVENT) {
data->event_count--;
return -ENOSPC;
}
list_add_tail(&int_ev->list, &data->events);
}
return 0;
}
static void rfkill_send_events(struct rfkill *rfkill, enum rfkill_operation op)
@@ -282,10 +296,10 @@ static void rfkill_send_events(struct rfkill *rfkill, enum rfkill_operation op)
ev = kzalloc_obj(*ev);
if (!ev)
continue;
rfkill_fill_event(&ev->ev, rfkill, op);
mutex_lock(&data->mtx);
list_add_tail(&ev->list, &data->events);
mutex_unlock(&data->mtx);
if (rfkill_fill_event(ev, rfkill, data, op)) {
kfree(ev);
continue;
}
wake_up_interruptible(&data->read_wait);
}
}
@@ -1186,10 +1200,8 @@ static int rfkill_fop_open(struct inode *inode, struct file *file)
if (!ev)
goto free;
rfkill_sync(rfkill);
rfkill_fill_event(&ev->ev, rfkill, RFKILL_OP_ADD);
mutex_lock(&data->mtx);
list_add_tail(&ev->list, &data->events);
mutex_unlock(&data->mtx);
if (rfkill_fill_event(ev, rfkill, data, RFKILL_OP_ADD))
kfree(ev);
}
list_add(&data->list, &rfkill_fds);
mutex_unlock(&rfkill_global_mutex);
@@ -1259,6 +1271,7 @@ static ssize_t rfkill_fop_read(struct file *file, char __user *buf,
ret = -EFAULT;
list_del(&ev->list);
data->event_count--;
kfree(ev);
out:
mutex_unlock(&data->mtx);

View File

@@ -654,9 +654,6 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname,
goto success;
case RXRPC_SECURITY_KEY:
ret = -EINVAL;
if (rx->key)
goto error;
ret = -EISCONN;
if (rx->sk.sk_state != RXRPC_UNBOUND)
goto error;
@@ -664,9 +661,6 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname,
goto error;
case RXRPC_SECURITY_KEYRING:
ret = -EINVAL;
if (rx->key)
goto error;
ret = -EISCONN;
if (rx->sk.sk_state != RXRPC_UNBOUND)
goto error;

View File

@@ -117,7 +117,7 @@ struct rxrpc_net {
atomic_t stat_tx_jumbo[10];
atomic_t stat_rx_jumbo[10];
atomic_t stat_why_req_ack[8];
atomic_t stat_why_req_ack[9];
atomic_t stat_io_loop;
};

View File

@@ -654,11 +654,9 @@ void rxrpc_put_call(struct rxrpc_call *call, enum rxrpc_call_trace why)
if (dead) {
ASSERTCMP(__rxrpc_call_state(call), ==, RXRPC_CALL_COMPLETE);
if (!list_empty(&call->link)) {
spin_lock(&rxnet->call_lock);
list_del_init(&call->link);
spin_unlock(&rxnet->call_lock);
}
spin_lock(&rxnet->call_lock);
list_del_rcu(&call->link);
spin_unlock(&rxnet->call_lock);
rxrpc_cleanup_call(call);
}
@@ -694,6 +692,7 @@ static void rxrpc_destroy_call(struct work_struct *work)
rxrpc_put_bundle(call->bundle, rxrpc_bundle_put_call);
rxrpc_put_peer(call->peer, rxrpc_peer_put_call);
rxrpc_put_local(call->local, rxrpc_local_put_call);
key_put(call->key);
call_rcu(&call->rcu, rxrpc_rcu_free_call);
}
@@ -730,24 +729,20 @@ void rxrpc_destroy_all_calls(struct rxrpc_net *rxnet)
_enter("");
if (!list_empty(&rxnet->calls)) {
int shown = 0;
spin_lock(&rxnet->call_lock);
while (!list_empty(&rxnet->calls)) {
call = list_entry(rxnet->calls.next,
struct rxrpc_call, link);
_debug("Zapping call %p", call);
rxrpc_see_call(call, rxrpc_call_see_zap);
list_del_init(&call->link);
list_for_each_entry(call, &rxnet->calls, link) {
rxrpc_see_call(call, rxrpc_call_see_still_live);
pr_err("Call %p still in use (%d,%s,%lx,%lx)!\n",
call, refcount_read(&call->ref),
rxrpc_call_states[__rxrpc_call_state(call)],
call->flags, call->events);
spin_unlock(&rxnet->call_lock);
cond_resched();
spin_lock(&rxnet->call_lock);
if (++shown >= 10)
break;
}
spin_unlock(&rxnet->call_lock);

View File

@@ -247,6 +247,7 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
struct sk_buff *skb)
{
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
bool secured = false;
int ret;
if (conn->state == RXRPC_CONN_ABORTED)
@@ -262,6 +263,13 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
return ret;
case RXRPC_PACKET_TYPE_RESPONSE:
spin_lock_irq(&conn->state_lock);
if (conn->state != RXRPC_CONN_SERVICE_CHALLENGING) {
spin_unlock_irq(&conn->state_lock);
return 0;
}
spin_unlock_irq(&conn->state_lock);
ret = conn->security->verify_response(conn, skb);
if (ret < 0)
return ret;
@@ -272,11 +280,13 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
return ret;
spin_lock_irq(&conn->state_lock);
if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING)
if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING) {
conn->state = RXRPC_CONN_SERVICE;
secured = true;
}
spin_unlock_irq(&conn->state_lock);
if (conn->state == RXRPC_CONN_SERVICE) {
if (secured) {
/* Offload call state flipping to the I/O thread. As
* we've already received the packet, put it on the
* front of the queue.
@@ -557,11 +567,11 @@ void rxrpc_post_response(struct rxrpc_connection *conn, struct sk_buff *skb)
spin_lock_irq(&local->lock);
old = conn->tx_response;
if (old) {
struct rxrpc_skb_priv *osp = rxrpc_skb(skb);
struct rxrpc_skb_priv *osp = rxrpc_skb(old);
/* Always go with the response to the most recent challenge. */
if (after(sp->resp.challenge_serial, osp->resp.challenge_serial))
conn->tx_response = old;
conn->tx_response = skb;
else
old = skb;
} else {
@@ -569,4 +579,5 @@ void rxrpc_post_response(struct rxrpc_connection *conn, struct sk_buff *skb)
}
spin_unlock_irq(&local->lock);
rxrpc_poke_conn(conn, rxrpc_conn_get_poke_response);
rxrpc_free_skb(old, rxrpc_skb_put_old_response);
}

View File

@@ -413,6 +413,6 @@ void rxrpc_rack_timer_expired(struct rxrpc_call *call, ktime_t overran_by)
break;
//case RXRPC_CALL_RACKTIMER_ZEROWIN:
default:
pr_warn("Unexpected rack timer %u", call->rack_timer_mode);
pr_warn("Unexpected rack timer %u", mode);
}
}

View File

@@ -419,7 +419,8 @@ static int rxrpc_input_packet_on_conn(struct rxrpc_connection *conn,
if (sp->hdr.callNumber > chan->call_id) {
if (rxrpc_to_client(sp)) {
rxrpc_put_call(call, rxrpc_call_put_input);
if (call)
rxrpc_put_call(call, rxrpc_call_put_input);
return rxrpc_protocol_error(skb,
rxrpc_eproto_unexpected_implicit_end);
}

View File

@@ -13,6 +13,7 @@
#include <crypto/skcipher.h>
#include <linux/module.h>
#include <linux/net.h>
#include <linux/overflow.h>
#include <linux/skbuff.h>
#include <linux/key-type.h>
#include <linux/ctype.h>
@@ -72,7 +73,7 @@ static int rxrpc_preparse_xdr_rxkad(struct key_preparsed_payload *prep,
return -EKEYREJECTED;
plen = sizeof(*token) + sizeof(*token->kad) + tktlen;
prep->quotalen = datalen + plen;
prep->quotalen += datalen + plen;
plen -= sizeof(*token);
token = kzalloc_obj(*token);
@@ -171,7 +172,7 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
size_t plen;
const __be32 *ticket, *key;
s64 tmp;
u32 tktlen, keylen;
size_t raw_keylen, raw_tktlen, keylen, tktlen;
_enter(",{%x,%x,%x,%x},%x",
ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
@@ -181,32 +182,36 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
goto reject;
key = xdr + (6 * 2 + 1);
keylen = ntohl(key[-1]);
_debug("keylen: %x", keylen);
keylen = round_up(keylen, 4);
raw_keylen = ntohl(key[-1]);
_debug("keylen: %zx", raw_keylen);
if (raw_keylen > AFSTOKEN_GK_KEY_MAX)
goto reject;
keylen = round_up(raw_keylen, 4);
if ((6 * 2 + 2) * 4 + keylen > toklen)
goto reject;
ticket = xdr + (6 * 2 + 1 + (keylen / 4) + 1);
tktlen = ntohl(ticket[-1]);
_debug("tktlen: %x", tktlen);
tktlen = round_up(tktlen, 4);
raw_tktlen = ntohl(ticket[-1]);
_debug("tktlen: %zx", raw_tktlen);
if (raw_tktlen > AFSTOKEN_GK_TOKEN_MAX)
goto reject;
tktlen = round_up(raw_tktlen, 4);
if ((6 * 2 + 2) * 4 + keylen + tktlen != toklen) {
kleave(" = -EKEYREJECTED [%x!=%x, %x,%x]",
kleave(" = -EKEYREJECTED [%zx!=%x, %zx,%zx]",
(6 * 2 + 2) * 4 + keylen + tktlen, toklen,
keylen, tktlen);
goto reject;
}
plen = sizeof(*token) + sizeof(*token->rxgk) + tktlen + keylen;
prep->quotalen = datalen + plen;
prep->quotalen += datalen + plen;
plen -= sizeof(*token);
token = kzalloc_obj(*token);
if (!token)
goto nomem;
token->rxgk = kzalloc(sizeof(*token->rxgk) + keylen, GFP_KERNEL);
token->rxgk = kzalloc(struct_size_t(struct rxgk_key, _key, raw_keylen), GFP_KERNEL);
if (!token->rxgk)
goto nomem_token;
@@ -221,9 +226,9 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
token->rxgk->enctype = tmp = xdr_dec64(xdr + 5 * 2);
if (tmp < 0 || tmp > UINT_MAX)
goto reject_token;
token->rxgk->key.len = ntohl(key[-1]);
token->rxgk->key.len = raw_keylen;
token->rxgk->key.data = token->rxgk->_key;
token->rxgk->ticket.len = ntohl(ticket[-1]);
token->rxgk->ticket.len = raw_tktlen;
if (token->rxgk->endtime != 0) {
expiry = rxrpc_s64_to_time64(token->rxgk->endtime);
@@ -236,8 +241,7 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
memcpy(token->rxgk->key.data, key, token->rxgk->key.len);
/* Pad the ticket so that we can use it directly in XDR */
token->rxgk->ticket.data = kzalloc(round_up(token->rxgk->ticket.len, 4),
GFP_KERNEL);
token->rxgk->ticket.data = kzalloc(tktlen, GFP_KERNEL);
if (!token->rxgk->ticket.data)
goto nomem_yrxgk;
memcpy(token->rxgk->ticket.data, ticket, token->rxgk->ticket.len);
@@ -274,6 +278,7 @@ nomem_token:
nomem:
return -ENOMEM;
reject_token:
kfree(token->rxgk);
kfree(token);
reject:
return -EKEYREJECTED;
@@ -460,6 +465,7 @@ static int rxrpc_preparse(struct key_preparsed_payload *prep)
memcpy(&kver, prep->data, sizeof(kver));
prep->data += sizeof(kver);
prep->datalen -= sizeof(kver);
prep->quotalen = 0;
_debug("KEY I/F VERSION: %u", kver);
@@ -497,7 +503,7 @@ static int rxrpc_preparse(struct key_preparsed_payload *prep)
goto error;
plen = sizeof(*token->kad) + v1->ticket_length;
prep->quotalen = plen + sizeof(*token);
prep->quotalen += plen + sizeof(*token);
ret = -ENOMEM;
token = kzalloc_obj(*token);
@@ -616,7 +622,7 @@ int rxrpc_request_key(struct rxrpc_sock *rx, sockptr_t optval, int optlen)
_enter("");
if (optlen <= 0 || optlen > PAGE_SIZE - 1 || rx->securities)
if (optlen <= 0 || optlen > PAGE_SIZE - 1 || rx->key)
return -EINVAL;
description = memdup_sockptr_nul(optval, optlen);

View File

@@ -479,6 +479,8 @@ static size_t rxrpc_prepare_data_subpacket(struct rxrpc_call *call,
why = rxrpc_reqack_old_rtt;
else if (!last && !after(READ_ONCE(call->send_top), txb->seq))
why = rxrpc_reqack_app_stall;
else if (call->tx_winsize <= (2 * req->n) || call->cong_cwnd <= (2 * req->n))
why = rxrpc_reqack_jumbo_win;
else
goto dont_set_request_ack;

View File

@@ -10,6 +10,10 @@
#include <net/af_rxrpc.h>
#include "ar-internal.h"
#define RXRPC_PROC_ADDRBUF_SIZE \
(sizeof("[xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255]") + \
sizeof(":12345"))
static const char *const rxrpc_conn_states[RXRPC_CONN__NR_STATES] = {
[RXRPC_CONN_UNUSED] = "Unused ",
[RXRPC_CONN_CLIENT_UNSECURED] = "ClUnsec ",
@@ -53,7 +57,7 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
enum rxrpc_call_state state;
rxrpc_seq_t tx_bottom;
char lbuff[50], rbuff[50];
char lbuff[RXRPC_PROC_ADDRBUF_SIZE], rbuff[RXRPC_PROC_ADDRBUF_SIZE];
long timeout = 0;
if (v == &rxnet->calls) {
@@ -69,11 +73,11 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
local = call->local;
if (local)
sprintf(lbuff, "%pISpc", &local->srx.transport);
scnprintf(lbuff, sizeof(lbuff), "%pISpc", &local->srx.transport);
else
strcpy(lbuff, "no_local");
sprintf(rbuff, "%pISpc", &call->dest_srx.transport);
scnprintf(rbuff, sizeof(rbuff), "%pISpc", &call->dest_srx.transport);
state = rxrpc_call_state(call);
if (state != RXRPC_CALL_SERVER_PREALLOC)
@@ -142,7 +146,7 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
struct rxrpc_connection *conn;
struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
const char *state;
char lbuff[50], rbuff[50];
char lbuff[RXRPC_PROC_ADDRBUF_SIZE], rbuff[RXRPC_PROC_ADDRBUF_SIZE];
if (v == &rxnet->conn_proc_list) {
seq_puts(seq,
@@ -161,8 +165,8 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
goto print;
}
sprintf(lbuff, "%pISpc", &conn->local->srx.transport);
sprintf(rbuff, "%pISpc", &conn->peer->srx.transport);
scnprintf(lbuff, sizeof(lbuff), "%pISpc", &conn->local->srx.transport);
scnprintf(rbuff, sizeof(rbuff), "%pISpc", &conn->peer->srx.transport);
print:
state = rxrpc_is_conn_aborted(conn) ?
rxrpc_call_completions[conn->completion] :
@@ -228,7 +232,7 @@ static int rxrpc_bundle_seq_show(struct seq_file *seq, void *v)
{
struct rxrpc_bundle *bundle;
struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
char lbuff[50], rbuff[50];
char lbuff[RXRPC_PROC_ADDRBUF_SIZE], rbuff[RXRPC_PROC_ADDRBUF_SIZE];
if (v == &rxnet->bundle_proc_list) {
seq_puts(seq,
@@ -242,8 +246,8 @@ static int rxrpc_bundle_seq_show(struct seq_file *seq, void *v)
bundle = list_entry(v, struct rxrpc_bundle, proc_link);
sprintf(lbuff, "%pISpc", &bundle->local->srx.transport);
sprintf(rbuff, "%pISpc", &bundle->peer->srx.transport);
scnprintf(lbuff, sizeof(lbuff), "%pISpc", &bundle->local->srx.transport);
scnprintf(rbuff, sizeof(rbuff), "%pISpc", &bundle->peer->srx.transport);
seq_printf(seq,
"UDP %-47.47s %-47.47s %4x %3u %3d"
" %c%c%c %08x | %08x %08x %08x %08x %08x\n",
@@ -279,7 +283,7 @@ static int rxrpc_peer_seq_show(struct seq_file *seq, void *v)
{
struct rxrpc_peer *peer;
time64_t now;
char lbuff[50], rbuff[50];
char lbuff[RXRPC_PROC_ADDRBUF_SIZE], rbuff[RXRPC_PROC_ADDRBUF_SIZE];
if (v == SEQ_START_TOKEN) {
seq_puts(seq,
@@ -290,9 +294,9 @@ static int rxrpc_peer_seq_show(struct seq_file *seq, void *v)
peer = list_entry(v, struct rxrpc_peer, hash_link);
sprintf(lbuff, "%pISpc", &peer->local->srx.transport);
scnprintf(lbuff, sizeof(lbuff), "%pISpc", &peer->local->srx.transport);
sprintf(rbuff, "%pISpc", &peer->srx.transport);
scnprintf(rbuff, sizeof(rbuff), "%pISpc", &peer->srx.transport);
now = ktime_get_seconds();
seq_printf(seq,
@@ -401,7 +405,7 @@ const struct seq_operations rxrpc_peer_seq_ops = {
static int rxrpc_local_seq_show(struct seq_file *seq, void *v)
{
struct rxrpc_local *local;
char lbuff[50];
char lbuff[RXRPC_PROC_ADDRBUF_SIZE];
if (v == SEQ_START_TOKEN) {
seq_puts(seq,
@@ -412,7 +416,7 @@ static int rxrpc_local_seq_show(struct seq_file *seq, void *v)
local = hlist_entry(v, struct rxrpc_local, link);
sprintf(lbuff, "%pISpc", &local->srx.transport);
scnprintf(lbuff, sizeof(lbuff), "%pISpc", &local->srx.transport);
seq_printf(seq,
"UDP %-47.47s %3u %3u %3u\n",
@@ -518,11 +522,12 @@ int rxrpc_stats_show(struct seq_file *seq, void *v)
atomic_read(&rxnet->stat_rx_acks[RXRPC_ACK_IDLE]),
atomic_read(&rxnet->stat_rx_acks[0]));
seq_printf(seq,
"Why-Req-A: acklost=%u mrtt=%u ortt=%u stall=%u\n",
"Why-Req-A: acklost=%u mrtt=%u ortt=%u stall=%u jwin=%u\n",
atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_ack_lost]),
atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_more_rtt]),
atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_old_rtt]),
atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_app_stall]));
atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_app_stall]),
atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_jumbo_win]));
seq_printf(seq,
"Why-Req-A: nolast=%u retx=%u slows=%u smtxw=%u\n",
atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_no_srv_last]),

View File

@@ -1085,6 +1085,9 @@ static int rxgk_do_verify_authenticator(struct rxrpc_connection *conn,
_enter("");
if ((end - p) * sizeof(__be32) < 24)
return rxrpc_abort_conn(conn, skb, RXGK_NOTAUTH, -EPROTO,
rxgk_abort_resp_short_auth);
if (memcmp(p, conn->rxgk.nonce, 20) != 0)
return rxrpc_abort_conn(conn, skb, RXGK_NOTAUTH, -EPROTO,
rxgk_abort_resp_bad_nonce);
@@ -1098,7 +1101,7 @@ static int rxgk_do_verify_authenticator(struct rxrpc_connection *conn,
p += xdr_round_up(app_len) / sizeof(__be32);
if (end - p < 4)
return rxrpc_abort_conn(conn, skb, RXGK_NOTAUTH, -EPROTO,
rxgk_abort_resp_short_applen);
rxgk_abort_resp_short_auth);
level = ntohl(*p++);
epoch = ntohl(*p++);
@@ -1164,7 +1167,8 @@ static int rxgk_verify_authenticator(struct rxrpc_connection *conn,
}
p = auth;
ret = rxgk_do_verify_authenticator(conn, krb5, skb, p, p + auth_len);
ret = rxgk_do_verify_authenticator(conn, krb5, skb, p,
p + auth_len / sizeof(*p));
error:
kfree(auth);
return ret;
@@ -1208,7 +1212,8 @@ static int rxgk_verify_response(struct rxrpc_connection *conn,
token_offset = offset;
token_len = ntohl(rhdr.token_len);
if (xdr_round_up(token_len) + sizeof(__be32) > len)
if (token_len > len ||
xdr_round_up(token_len) + sizeof(__be32) > len)
goto short_packet;
trace_rxrpc_rx_response(conn, sp->hdr.serial, 0, sp->hdr.cksum, token_len);
@@ -1223,7 +1228,7 @@ static int rxgk_verify_response(struct rxrpc_connection *conn,
auth_offset = offset;
auth_len = ntohl(xauth_len);
if (auth_len < len)
if (auth_len > len)
goto short_packet;
if (auth_len & 3)
goto inconsistent;
@@ -1268,16 +1273,18 @@ static int rxgk_verify_response(struct rxrpc_connection *conn,
if (ret < 0) {
rxrpc_abort_conn(conn, skb, RXGK_SEALEDINCON, ret,
rxgk_abort_resp_auth_dec);
goto out;
goto out_gk;
}
ret = rxgk_verify_authenticator(conn, krb5, skb, auth_offset, auth_len);
if (ret < 0)
goto out;
goto out_gk;
conn->key = key;
key = NULL;
ret = 0;
out_gk:
rxgk_put(gk);
out:
key_put(key);
_leave(" = %d", ret);

View File

@@ -197,6 +197,7 @@ static int rxkad_prime_packet_security(struct rxrpc_connection *conn,
struct rxrpc_crypt iv;
__be32 *tmpbuf;
size_t tmpsize = 4 * sizeof(__be32);
int ret;
_enter("");
@@ -225,13 +226,13 @@ static int rxkad_prime_packet_security(struct rxrpc_connection *conn,
skcipher_request_set_sync_tfm(req, ci);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, &sg, &sg, tmpsize, iv.x);
crypto_skcipher_encrypt(req);
ret = crypto_skcipher_encrypt(req);
skcipher_request_free(req);
memcpy(&conn->rxkad.csum_iv, tmpbuf + 2, sizeof(conn->rxkad.csum_iv));
kfree(tmpbuf);
_leave(" = 0");
return 0;
_leave(" = %d", ret);
return ret;
}
/*
@@ -264,6 +265,7 @@ static int rxkad_secure_packet_auth(const struct rxrpc_call *call,
struct scatterlist sg;
size_t pad;
u16 check;
int ret;
_enter("");
@@ -286,11 +288,11 @@ static int rxkad_secure_packet_auth(const struct rxrpc_call *call,
skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
crypto_skcipher_encrypt(req);
ret = crypto_skcipher_encrypt(req);
skcipher_request_zero(req);
_leave(" = 0");
return 0;
_leave(" = %d", ret);
return ret;
}
/*
@@ -345,7 +347,7 @@ static int rxkad_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
union {
__be32 buf[2];
} crypto __aligned(8);
u32 x, y;
u32 x, y = 0;
int ret;
_enter("{%d{%x}},{#%u},%u,",
@@ -376,8 +378,10 @@ static int rxkad_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
crypto_skcipher_encrypt(req);
ret = crypto_skcipher_encrypt(req);
skcipher_request_zero(req);
if (ret < 0)
goto out;
y = ntohl(crypto.buf[1]);
y = (y >> 16) & 0xffff;
@@ -413,6 +417,7 @@ static int rxkad_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
memset(p + txb->pkt_len, 0, gap);
}
out:
skcipher_request_free(req);
_leave(" = %d [set %x]", ret, y);
return ret;
@@ -453,8 +458,10 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, sg, sg, 8, iv.x);
crypto_skcipher_decrypt(req);
ret = crypto_skcipher_decrypt(req);
skcipher_request_zero(req);
if (ret < 0)
return ret;
/* Extract the decrypted packet length */
if (skb_copy_bits(skb, sp->offset, &sechdr, sizeof(sechdr)) < 0)
@@ -531,10 +538,14 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, sg, sg, sp->len, iv.x);
crypto_skcipher_decrypt(req);
ret = crypto_skcipher_decrypt(req);
skcipher_request_zero(req);
if (sg != _sg)
kfree(sg);
if (ret < 0) {
WARN_ON_ONCE(ret != -ENOMEM);
return ret;
}
/* Extract the decrypted packet length */
if (skb_copy_bits(skb, sp->offset, &sechdr, sizeof(sechdr)) < 0)
@@ -602,8 +613,10 @@ static int rxkad_verify_packet(struct rxrpc_call *call, struct sk_buff *skb)
skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
crypto_skcipher_encrypt(req);
ret = crypto_skcipher_encrypt(req);
skcipher_request_zero(req);
if (ret < 0)
goto out;
y = ntohl(crypto.buf[1]);
cksum = (y >> 16) & 0xffff;
@@ -958,6 +971,7 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
struct in_addr addr;
unsigned int life;
time64_t issue, now;
int ret;
bool little_endian;
u8 *p, *q, *name, *end;
@@ -977,8 +991,11 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
sg_init_one(&sg[0], ticket, ticket_len);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, sg, sg, ticket_len, iv.x);
crypto_skcipher_decrypt(req);
ret = crypto_skcipher_decrypt(req);
skcipher_request_free(req);
if (ret < 0)
return rxrpc_abort_conn(conn, skb, RXKADBADTICKET, -EPROTO,
rxkad_abort_resp_tkt_short);
p = ticket;
end = p + ticket_len;
@@ -1073,21 +1090,23 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
/*
* decrypt the response packet
*/
static void rxkad_decrypt_response(struct rxrpc_connection *conn,
struct rxkad_response *resp,
const struct rxrpc_crypt *session_key)
static int rxkad_decrypt_response(struct rxrpc_connection *conn,
struct rxkad_response *resp,
const struct rxrpc_crypt *session_key)
{
struct skcipher_request *req = rxkad_ci_req;
struct scatterlist sg[1];
struct rxrpc_crypt iv;
int ret;
_enter(",,%08x%08x",
ntohl(session_key->n[0]), ntohl(session_key->n[1]));
mutex_lock(&rxkad_ci_mutex);
if (crypto_sync_skcipher_setkey(rxkad_ci, session_key->x,
sizeof(*session_key)) < 0)
BUG();
ret = crypto_sync_skcipher_setkey(rxkad_ci, session_key->x,
sizeof(*session_key));
if (ret < 0)
goto unlock;
memcpy(&iv, session_key, sizeof(iv));
@@ -1096,12 +1115,14 @@ static void rxkad_decrypt_response(struct rxrpc_connection *conn,
skcipher_request_set_sync_tfm(req, rxkad_ci);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, sg, sg, sizeof(resp->encrypted), iv.x);
crypto_skcipher_decrypt(req);
ret = crypto_skcipher_decrypt(req);
skcipher_request_zero(req);
unlock:
mutex_unlock(&rxkad_ci_mutex);
_leave("");
return ret;
}
/*
@@ -1194,7 +1215,9 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
/* use the session key from inside the ticket to decrypt the
* response */
rxkad_decrypt_response(conn, response, &session_key);
ret = rxkad_decrypt_response(conn, response, &session_key);
if (ret < 0)
goto temporary_error_free_ticket;
if (ntohl(response->encrypted.epoch) != conn->proto.epoch ||
ntohl(response->encrypted.cid) != conn->proto.cid ||

View File

@@ -637,7 +637,7 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,
memset(&cp, 0, sizeof(cp));
cp.local = rx->local;
cp.peer = peer;
cp.key = rx->key;
cp.key = key;
cp.security_level = rx->min_sec_level;
cp.exclusive = rx->exclusive | p->exclusive;
cp.upgrade = p->upgrade;

View File

@@ -125,6 +125,9 @@ int rxrpc_server_keyring(struct rxrpc_sock *rx, sockptr_t optval, int optlen)
_enter("");
if (rx->securities)
return -EINVAL;
if (optlen <= 0 || optlen > PAGE_SIZE - 1)
return -EINVAL;

View File

@@ -604,8 +604,12 @@ again:
protocol = skb->protocol;
orig_vlan_tag_present = true;
} else {
struct vlan_hdr *vlan = (struct vlan_hdr *)skb->data;
struct vlan_hdr *vlan;
if (!pskb_may_pull(skb, VLAN_HLEN))
goto drop;
vlan = (struct vlan_hdr *)skb->data;
protocol = vlan->h_vlan_encapsulated_proto;
skb_pull(skb, VLAN_HLEN);
skb_reset_network_header(skb);

View File

@@ -746,6 +746,7 @@ void tipc_group_proto_rcv(struct tipc_group *grp, bool *usr_wakeup,
u32 port = msg_origport(hdr);
struct tipc_member *m, *pm;
u16 remitted, in_flight;
u16 acked;
if (!grp)
return;
@@ -798,7 +799,10 @@ void tipc_group_proto_rcv(struct tipc_group *grp, bool *usr_wakeup,
case GRP_ACK_MSG:
if (!m)
return;
m->bc_acked = msg_grp_bc_acked(hdr);
acked = msg_grp_bc_acked(hdr);
if (less_eq(acked, m->bc_acked))
return;
m->bc_acked = acked;
if (--grp->bc_ackers)
return;
list_del_init(&m->small_win);

View File

@@ -584,6 +584,16 @@ static int tls_do_encryption(struct sock *sk,
if (rc == -EBUSY) {
rc = tls_encrypt_async_wait(ctx);
rc = rc ?: -EINPROGRESS;
/*
* The async callback tls_encrypt_done() has already
* decremented encrypt_pending and restored the sge on
* both success and error. Skip the synchronous cleanup
* below on error, just remove the record and return.
*/
if (rc != -EINPROGRESS) {
list_del(&rec->list);
return rc;
}
}
if (!rc || rc != -EINPROGRESS) {
atomic_dec(&ctx->encrypt_pending);

View File

@@ -28,18 +28,23 @@ static int sk_diag_dump_name(struct sock *sk, struct sk_buff *nlskb)
static int sk_diag_dump_vfs(struct sock *sk, struct sk_buff *nlskb)
{
struct dentry *dentry = unix_sk(sk)->path.dentry;
struct unix_diag_vfs uv;
struct dentry *dentry;
bool have_vfs = false;
unix_state_lock(sk);
dentry = unix_sk(sk)->path.dentry;
if (dentry) {
struct unix_diag_vfs uv = {
.udiag_vfs_ino = d_backing_inode(dentry)->i_ino,
.udiag_vfs_dev = dentry->d_sb->s_dev,
};
return nla_put(nlskb, UNIX_DIAG_VFS, sizeof(uv), &uv);
uv.udiag_vfs_ino = d_backing_inode(dentry)->i_ino;
uv.udiag_vfs_dev = dentry->d_sb->s_dev;
have_vfs = true;
}
unix_state_unlock(sk);
return 0;
if (!have_vfs)
return 0;
return nla_put(nlskb, UNIX_DIAG_VFS, sizeof(uv), &uv);
}
static int sk_diag_dump_peer(struct sock *sk, struct sk_buff *nlskb)

View File

@@ -203,7 +203,8 @@ static int xdp_umem_reg(struct xdp_umem *umem, struct xdp_umem_reg *mr)
if (!unaligned_chunks && chunks_rem)
return -EINVAL;
if (headroom >= chunk_size - XDP_PACKET_HEADROOM)
if (headroom > chunk_size - XDP_PACKET_HEADROOM -
SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) - 128)
return -EINVAL;
if (mr->flags & XDP_UMEM_TX_METADATA_LEN) {

View File

@@ -239,7 +239,7 @@ static u32 xsk_copy_xdp(void *to, void **from, u32 to_len,
static int __xsk_rcv(struct xdp_sock *xs, struct xdp_buff *xdp, u32 len)
{
u32 frame_size = xsk_pool_get_rx_frame_size(xs->pool);
u32 frame_size = __xsk_pool_get_rx_frame_size(xs->pool);
void *copy_from = xsk_copy_xdp_start(xdp), *copy_to;
u32 from_len, meta_len, rem, num_desc;
struct xdp_buff_xsk *xskb;
@@ -338,7 +338,7 @@ static int xsk_rcv_check(struct xdp_sock *xs, struct xdp_buff *xdp, u32 len)
if (xs->dev != xdp->rxq->dev || xs->queue_id != xdp->rxq->queue_index)
return -EINVAL;
if (len > xsk_pool_get_rx_frame_size(xs->pool) && !xs->sg) {
if (len > __xsk_pool_get_rx_frame_size(xs->pool) && !xs->sg) {
xs->rx_dropped++;
return -ENOSPC;
}

View File

@@ -10,6 +10,8 @@
#include "xdp_umem.h"
#include "xsk.h"
#define ETH_PAD_LEN (ETH_HLEN + 2 * VLAN_HLEN + ETH_FCS_LEN)
void xp_add_xsk(struct xsk_buff_pool *pool, struct xdp_sock *xs)
{
if (!xs->tx)
@@ -157,8 +159,12 @@ static void xp_disable_drv_zc(struct xsk_buff_pool *pool)
int xp_assign_dev(struct xsk_buff_pool *pool,
struct net_device *netdev, u16 queue_id, u16 flags)
{
u32 needed = netdev->mtu + ETH_PAD_LEN;
u32 segs = netdev->xdp_zc_max_segs;
bool mbuf = flags & XDP_USE_SG;
bool force_zc, force_copy;
struct netdev_bpf bpf;
u32 frame_size;
int err = 0;
ASSERT_RTNL();
@@ -178,7 +184,7 @@ int xp_assign_dev(struct xsk_buff_pool *pool,
if (err)
return err;
if (flags & XDP_USE_SG)
if (mbuf)
pool->umem->flags |= XDP_UMEM_SG_FLAG;
if (flags & XDP_USE_NEED_WAKEUP)
@@ -200,8 +206,24 @@ int xp_assign_dev(struct xsk_buff_pool *pool,
goto err_unreg_pool;
}
if (netdev->xdp_zc_max_segs == 1 && (flags & XDP_USE_SG)) {
err = -EOPNOTSUPP;
if (mbuf) {
if (segs == 1) {
err = -EOPNOTSUPP;
goto err_unreg_pool;
}
} else {
segs = 1;
}
/* open-code xsk_pool_get_rx_frame_size() as pool->dev is not
* set yet at this point; we are before getting down to driver
*/
frame_size = __xsk_pool_get_rx_frame_size(pool) -
xsk_pool_get_tailroom(mbuf);
frame_size = ALIGN_DOWN(frame_size, 128);
if (needed > frame_size * segs) {
err = -EINVAL;
goto err_unreg_pool;
}
@@ -247,6 +269,10 @@ int xp_assign_dev_shared(struct xsk_buff_pool *pool, struct xdp_sock *umem_xs,
struct xdp_umem *umem = umem_xs->umem;
flags = umem->zc ? XDP_ZEROCOPY : XDP_COPY;
if (umem->flags & XDP_UMEM_SG_FLAG)
flags |= XDP_USE_SG;
if (umem_xs->pool->uses_need_wakeup)
flags |= XDP_USE_NEED_WAKEUP;

View File

@@ -506,7 +506,6 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
/* An encap_type of -1 indicates async resumption. */
if (encap_type == -1) {
async = 1;
dev_put(skb->dev);
seq = XFRM_SKB_CB(skb)->seq.input.low;
spin_lock(&x->lock);
goto resume;
@@ -659,8 +658,11 @@ process:
dev_hold(skb->dev);
nexthdr = x->type->input(x, skb);
if (nexthdr == -EINPROGRESS)
if (nexthdr == -EINPROGRESS) {
if (async)
dev_put(skb->dev);
return 0;
}
dev_put(skb->dev);
spin_lock(&x->lock);
@@ -695,9 +697,11 @@ resume:
XFRM_MODE_SKB_CB(skb)->protocol = nexthdr;
err = xfrm_inner_mode_input(x, skb);
if (err == -EINPROGRESS)
if (err == -EINPROGRESS) {
if (async)
dev_put(skb->dev);
return 0;
else if (err) {
} else if (err) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR);
goto drop;
}
@@ -734,6 +738,8 @@ resume_decapped:
sp->olen = 0;
if (skb_valid_dst(skb))
skb_dst_drop(skb);
if (async)
dev_put(skb->dev);
gro_cells_receive(&gro_cells, skb);
return 0;
} else {
@@ -753,6 +759,8 @@ resume_decapped:
sp->olen = 0;
if (skb_valid_dst(skb))
skb_dst_drop(skb);
if (async)
dev_put(skb->dev);
gro_cells_receive(&gro_cells, skb);
return err;
}
@@ -763,6 +771,8 @@ resume_decapped:
drop_unlock:
spin_unlock(&x->lock);
drop:
if (async)
dev_put(skb->dev);
xfrm_rcv_cb(skb, family, x && x->type ? x->type->proto : nexthdr, -1);
kfree_skb(skb);
return 0;

View File

@@ -4290,6 +4290,8 @@ static void xfrm_policy_fini(struct net *net)
#endif
xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, false);
synchronize_rcu();
WARN_ON(!list_empty(&net->xfrm.policy_all));
for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
@@ -4526,9 +4528,6 @@ static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector *
pol = xfrm_policy_lookup_bytype(net, type, &fl, sel->family, dir, if_id);
if (IS_ERR_OR_NULL(pol))
goto out_unlock;
if (!xfrm_pol_hold_rcu(pol))
pol = NULL;
out_unlock:
rcu_read_unlock();
return pol;

View File

@@ -2677,7 +2677,8 @@ static inline unsigned int xfrm_aevent_msgsize(struct xfrm_state *x)
+ nla_total_size(4) /* XFRM_AE_RTHR */
+ nla_total_size(4) /* XFRM_AE_ETHR */
+ nla_total_size(sizeof(x->dir)) /* XFRMA_SA_DIR */
+ nla_total_size(4); /* XFRMA_SA_PCPU */
+ nla_total_size(4) /* XFRMA_SA_PCPU */
+ nla_total_size(sizeof(x->if_id)); /* XFRMA_IF_ID */
}
static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, const struct km_event *c)
@@ -2789,7 +2790,12 @@ static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
c.portid = nlh->nlmsg_pid;
err = build_aevent(r_skb, x, &c);
BUG_ON(err < 0);
if (err < 0) {
spin_unlock_bh(&x->lock);
xfrm_state_put(x);
kfree_skb(r_skb);
return err;
}
err = nlmsg_unicast(xfrm_net_nlsk(net, skb), r_skb, NETLINK_CB(skb).portid);
spin_unlock_bh(&x->lock);
@@ -3960,6 +3966,8 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp,
return err;
}
upe->hard = !!hard;
/* clear the padding bytes */
memset_after(upe, 0, hard);
nlmsg_end(skb, nlh);
return 0;
@@ -4117,6 +4125,7 @@ static int build_report(struct sk_buff *skb, u8 proto,
return -EMSGSIZE;
ur = nlmsg_data(nlh);
memset(ur, 0, sizeof(*ur));
ur->proto = proto;
memcpy(&ur->sel, sel, sizeof(ur->sel));
@@ -4164,6 +4173,7 @@ static int build_mapping(struct sk_buff *skb, struct xfrm_state *x,
um = nlmsg_data(nlh);
memset(&um->id, 0, sizeof(um->id));
memcpy(&um->id.daddr, &x->id.daddr, sizeof(um->id.daddr));
um->id.spi = x->id.spi;
um->id.family = x->props.family;

View File

@@ -179,25 +179,6 @@ int xsk_configure_socket(struct xsk_socket_info *xsk, struct xsk_umem_info *umem
return xsk_socket__create(&xsk->xsk, ifobject->ifindex, 0, umem->umem, rxr, txr, &cfg);
}
#define MAX_SKB_FRAGS_PATH "/proc/sys/net/core/max_skb_frags"
static unsigned int get_max_skb_frags(void)
{
unsigned int max_skb_frags = 0;
FILE *file;
file = fopen(MAX_SKB_FRAGS_PATH, "r");
if (!file) {
ksft_print_msg("Error opening %s\n", MAX_SKB_FRAGS_PATH);
return 0;
}
if (fscanf(file, "%u", &max_skb_frags) != 1)
ksft_print_msg("Error reading %s\n", MAX_SKB_FRAGS_PATH);
fclose(file);
return max_skb_frags;
}
static int set_ring_size(struct ifobject *ifobj)
{
int ret;
@@ -1978,15 +1959,17 @@ int testapp_headroom(struct test_spec *test)
int testapp_stats_rx_dropped(struct test_spec *test)
{
u32 umem_tr = test->ifobj_tx->umem_tailroom;
if (test->mode == TEST_MODE_ZC) {
ksft_print_msg("Can not run RX_DROPPED test for ZC mode\n");
return TEST_SKIP;
}
if (pkt_stream_replace_half(test, MIN_PKT_SIZE * 4, 0))
if (pkt_stream_replace_half(test, (MIN_PKT_SIZE * 3) + umem_tr, 0))
return TEST_FAILURE;
test->ifobj_rx->umem->frame_headroom = test->ifobj_rx->umem->frame_size -
XDP_PACKET_HEADROOM - MIN_PKT_SIZE * 3;
XDP_PACKET_HEADROOM - (MIN_PKT_SIZE * 2) - umem_tr;
if (pkt_stream_receive_half(test))
return TEST_FAILURE;
test->ifobj_rx->validation_func = validate_rx_dropped;
@@ -2242,11 +2225,7 @@ int testapp_too_many_frags(struct test_spec *test)
if (test->mode == TEST_MODE_ZC) {
max_frags = test->ifobj_tx->xdp_zc_max_segs;
} else {
max_frags = get_max_skb_frags();
if (!max_frags) {
ksft_print_msg("Can't get MAX_SKB_FRAGS from system, using default (17)\n");
max_frags = 17;
}
max_frags = test->ifobj_tx->max_skb_frags;
max_frags += 1;
}
@@ -2551,16 +2530,34 @@ int testapp_adjust_tail_shrink_mb(struct test_spec *test)
int testapp_adjust_tail_grow(struct test_spec *test)
{
if (test->mode == TEST_MODE_SKB)
return TEST_SKIP;
/* Grow by 4 bytes for testing purpose */
return testapp_adjust_tail(test, 4, MIN_PKT_SIZE * 2);
}
int testapp_adjust_tail_grow_mb(struct test_spec *test)
{
u32 grow_size;
if (test->mode == TEST_MODE_SKB)
return TEST_SKIP;
/* worst case scenario is when underlying setup will work on 3k
* buffers, let us account for it; given that we will use 6k as
* pkt_len, expect that it will be broken down to 2 descs each
* with 3k payload;
*
* 4k is truesize, 3k payload, 256 HR, 320 TR;
*/
grow_size = XSK_UMEM__MAX_FRAME_SIZE -
XSK_UMEM__LARGE_FRAME_SIZE -
XDP_PACKET_HEADROOM -
test->ifobj_tx->umem_tailroom;
test->mtu = MAX_ETH_JUMBO_SIZE;
/* Grow by (frag_size - last_frag_Size) - 1 to stay inside the last fragment */
return testapp_adjust_tail(test, (XSK_UMEM__MAX_FRAME_SIZE / 2) - 1,
XSK_UMEM__LARGE_FRAME_SIZE * 2);
return testapp_adjust_tail(test, grow_size, XSK_UMEM__LARGE_FRAME_SIZE * 2);
}
int testapp_tx_queue_consumer(struct test_spec *test)

View File

@@ -31,6 +31,9 @@
#define SOCK_RECONF_CTR 10
#define USLEEP_MAX 10000
#define MAX_SKB_FRAGS_PATH "/proc/sys/net/core/max_skb_frags"
#define SMP_CACHE_BYTES_PATH "/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size"
extern bool opt_verbose;
#define print_verbose(x...) do { if (opt_verbose) ksft_print_msg(x); } while (0)
@@ -45,6 +48,24 @@ static inline u64 ceil_u64(u64 a, u64 b)
return (a + b - 1) / b;
}
static inline unsigned int read_procfs_val(const char *path)
{
unsigned int read_val = 0;
FILE *file;
file = fopen(path, "r");
if (!file) {
ksft_print_msg("Error opening %s\n", path);
return 0;
}
if (fscanf(file, "%u", &read_val) != 1)
ksft_print_msg("Error reading %s\n", path);
fclose(file);
return read_val;
}
/* Simple test */
enum test_mode {
TEST_MODE_SKB,
@@ -115,6 +136,8 @@ struct ifobject {
int mtu;
u32 bind_flags;
u32 xdp_zc_max_segs;
u32 umem_tailroom;
u32 max_skb_frags;
bool tx_on;
bool rx_on;
bool use_poll;

View File

@@ -62,6 +62,7 @@ int configure_ifobj(struct ifobject *tx, struct ifobject *rx)
static void test_xsk(const struct test_spec *test_to_run, enum test_mode mode)
{
u32 max_frags, umem_tailroom, cache_line_size;
struct ifobject *ifobj_tx, *ifobj_rx;
struct test_spec test;
int ret;
@@ -84,6 +85,24 @@ static void test_xsk(const struct test_spec *test_to_run, enum test_mode mode)
ifobj_tx->set_ring.default_rx = ifobj_tx->ring.rx_pending;
}
cache_line_size = read_procfs_val(SMP_CACHE_BYTES_PATH);
if (!cache_line_size)
cache_line_size = 64;
max_frags = read_procfs_val(MAX_SKB_FRAGS_PATH);
if (!max_frags)
max_frags = 17;
ifobj_tx->max_skb_frags = max_frags;
ifobj_rx->max_skb_frags = max_frags;
/* 48 bytes is a part of skb_shared_info w/o frags array;
* 16 bytes is sizeof(skb_frag_t)
*/
umem_tailroom = ALIGN(48 + (max_frags * 16), cache_line_size);
ifobj_tx->umem_tailroom = umem_tailroom;
ifobj_rx->umem_tailroom = umem_tailroom;
if (!ASSERT_OK(init_iface(ifobj_rx, worker_testapp_validate_rx), "init RX"))
goto delete_rx;
if (!ASSERT_OK(init_iface(ifobj_tx, worker_testapp_validate_tx), "init TX"))

View File

@@ -26,8 +26,10 @@ SEC("xdp.frags") int xsk_def_prog(struct xdp_md *xdp)
SEC("xdp.frags") int xsk_xdp_drop(struct xdp_md *xdp)
{
static unsigned int drop_idx;
/* Drop every other packet */
if (idx++ % 2)
if (drop_idx++ % 2)
return XDP_DROP;
return bpf_redirect_map(&xsk, 0, XDP_DROP);

View File

@@ -80,6 +80,7 @@
#include <linux/mman.h>
#include <linux/netdev.h>
#include <linux/ethtool.h>
#include <linux/align.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <locale.h>
@@ -333,6 +334,7 @@ static void print_tests(void)
int main(int argc, char **argv)
{
const size_t total_tests = ARRAY_SIZE(tests) + ARRAY_SIZE(ci_skip_tests);
u32 cache_line_size, max_frags, umem_tailroom;
struct pkt_stream *rx_pkt_stream_default;
struct pkt_stream *tx_pkt_stream_default;
struct ifobject *ifobj_tx, *ifobj_rx;
@@ -354,6 +356,27 @@ int main(int argc, char **argv)
setlocale(LC_ALL, "");
cache_line_size = read_procfs_val(SMP_CACHE_BYTES_PATH);
if (!cache_line_size) {
ksft_print_msg("Can't get SMP_CACHE_BYTES from system, using default (64)\n");
cache_line_size = 64;
}
max_frags = read_procfs_val(MAX_SKB_FRAGS_PATH);
if (!max_frags) {
ksft_print_msg("Can't get MAX_SKB_FRAGS from system, using default (17)\n");
max_frags = 17;
}
ifobj_tx->max_skb_frags = max_frags;
ifobj_rx->max_skb_frags = max_frags;
/* 48 bytes is a part of skb_shared_info w/o frags array;
* 16 bytes is sizeof(skb_frag_t)
*/
umem_tailroom = ALIGN(48 + (max_frags * 16), cache_line_size);
ifobj_tx->umem_tailroom = umem_tailroom;
ifobj_rx->umem_tailroom = umem_tailroom;
parse_command_line(ifobj_tx, ifobj_rx, argc, argv);
if (opt_print_tests) {

View File

@@ -89,6 +89,7 @@ TEST_PROGS := \
srv6_end_x_next_csid_l3vpn_test.sh \
srv6_hencap_red_l3vpn_test.sh \
srv6_hl2encap_red_l2vpn_test.sh \
srv6_iptunnel_cache.sh \
stress_reuseport_listen.sh \
tcp_fastopen_backup_key.sh \
test_bpf.sh \

View File

@@ -414,6 +414,7 @@ vlmc_querier_intvl_test()
bridge vlan add vid 10 dev br1 self pvid untagged
ip link set dev $h1 master br1
ip link set dev br1 up
setup_wait_dev $h1 0
bridge vlan add vid 10 dev $h1 master
bridge vlan global set vid 10 dev br1 mcast_snooping 1 mcast_querier 1
sleep 2

View File

@@ -19,6 +19,8 @@ struct options {
bool count_packets;
bool gso_enabled;
bool failopen;
bool out_of_order;
bool bogus_verdict;
int verbose;
unsigned int queue_num;
unsigned int timeout;
@@ -31,7 +33,7 @@ static struct options opts;
static void help(const char *p)
{
printf("Usage: %s [-c|-v [-vv] ] [-o] [-t timeout] [-q queue_num] [-Qdst_queue ] [ -d ms_delay ] [-G]\n", p);
printf("Usage: %s [-c|-v [-vv] ] [-o] [-O] [-b] [-t timeout] [-q queue_num] [-Qdst_queue ] [ -d ms_delay ] [-G]\n", p);
}
static int parse_attr_cb(const struct nlattr *attr, void *data)
@@ -275,7 +277,9 @@ static int mainloop(void)
unsigned int buflen = 64 * 1024 + MNL_SOCKET_BUFFER_SIZE;
struct mnl_socket *nl;
struct nlmsghdr *nlh;
uint32_t ooo_ids[16];
unsigned int portid;
int ooo_count = 0;
char *buf;
int ret;
@@ -308,6 +312,9 @@ static int mainloop(void)
ret = mnl_cb_run(buf, ret, 0, portid, queue_cb, NULL);
if (ret < 0) {
/* bogus verdict mode will generate ENOENT error messages */
if (opts.bogus_verdict && errno == ENOENT)
continue;
perror("mnl_cb_run");
exit(EXIT_FAILURE);
}
@@ -316,10 +323,35 @@ static int mainloop(void)
if (opts.delay_ms)
sleep_ms(opts.delay_ms);
nlh = nfq_build_verdict(buf, id, opts.queue_num, opts.verdict);
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
perror("mnl_socket_sendto");
exit(EXIT_FAILURE);
if (opts.bogus_verdict) {
for (int i = 0; i < 50; i++) {
nlh = nfq_build_verdict(buf, id + 0x7FFFFFFF + i,
opts.queue_num, opts.verdict);
mnl_socket_sendto(nl, nlh, nlh->nlmsg_len);
}
}
if (opts.out_of_order) {
ooo_ids[ooo_count] = id;
if (ooo_count >= 15) {
for (ooo_count; ooo_count >= 0; ooo_count--) {
nlh = nfq_build_verdict(buf, ooo_ids[ooo_count],
opts.queue_num, opts.verdict);
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
perror("mnl_socket_sendto");
exit(EXIT_FAILURE);
}
}
ooo_count = 0;
} else {
ooo_count++;
}
} else {
nlh = nfq_build_verdict(buf, id, opts.queue_num, opts.verdict);
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
perror("mnl_socket_sendto");
exit(EXIT_FAILURE);
}
}
}
@@ -332,7 +364,7 @@ static void parse_opts(int argc, char **argv)
{
int c;
while ((c = getopt(argc, argv, "chvot:q:Q:d:G")) != -1) {
while ((c = getopt(argc, argv, "chvoObt:q:Q:d:G")) != -1) {
switch (c) {
case 'c':
opts.count_packets = true;
@@ -375,6 +407,12 @@ static void parse_opts(int argc, char **argv)
case 'v':
opts.verbose++;
break;
case 'O':
opts.out_of_order = true;
break;
case 'b':
opts.bogus_verdict = true;
break;
}
}

View File

@@ -11,6 +11,7 @@ ret=0
timeout=5
SCTP_TEST_TIMEOUT=60
STRESS_TEST_TIMEOUT=30
cleanup()
{
@@ -719,6 +720,74 @@ EOF
fi
}
check_tainted()
{
local msg="$1"
if [ "$tainted_then" -ne 0 ];then
return
fi
read tainted_now < /proc/sys/kernel/tainted
if [ "$tainted_now" -eq 0 ];then
echo "PASS: $msg"
else
echo "TAINT: $msg"
dmesg
ret=1
fi
}
test_queue_stress()
{
read tainted_then < /proc/sys/kernel/tainted
local i
ip netns exec "$nsrouter" nft -f /dev/stdin <<EOF
flush ruleset
table inet t {
chain forward {
type filter hook forward priority 0; policy accept;
queue flags bypass to numgen random mod 8
}
}
EOF
timeout "$STRESS_TEST_TIMEOUT" ip netns exec "$ns2" \
socat -u UDP-LISTEN:12345,fork,pf=ipv4 STDOUT > /dev/null &
timeout "$STRESS_TEST_TIMEOUT" ip netns exec "$ns3" \
socat -u UDP-LISTEN:12345,fork,pf=ipv4 STDOUT > /dev/null &
for i in $(seq 0 7); do
ip netns exec "$nsrouter" timeout "$STRESS_TEST_TIMEOUT" \
./nf_queue -q $i -t 2 -O -b > /dev/null &
done
ip netns exec "$ns1" timeout "$STRESS_TEST_TIMEOUT" \
ping -q -f 10.0.2.99 > /dev/null 2>&1 &
ip netns exec "$ns1" timeout "$STRESS_TEST_TIMEOUT" \
ping -q -f 10.0.3.99 > /dev/null 2>&1 &
ip netns exec "$ns1" timeout "$STRESS_TEST_TIMEOUT" \
ping -q -f "dead:2::99" > /dev/null 2>&1 &
ip netns exec "$ns1" timeout "$STRESS_TEST_TIMEOUT" \
ping -q -f "dead:3::99" > /dev/null 2>&1 &
busywait "$BUSYWAIT_TIMEOUT" udp_listener_ready "$ns2" 12345
busywait "$BUSYWAIT_TIMEOUT" udp_listener_ready "$ns3" 12345
for i in $(seq 1 4);do
ip netns exec "$ns1" timeout "$STRESS_TEST_TIMEOUT" \
socat -u STDIN UDP-DATAGRAM:10.0.2.99:12345 < /dev/zero > /dev/null &
ip netns exec "$ns1" timeout "$STRESS_TEST_TIMEOUT" \
socat -u STDIN UDP-DATAGRAM:10.0.3.99:12345 < /dev/zero > /dev/null &
done
wait
check_tainted "concurrent queueing"
}
test_queue_removal()
{
read tainted_then < /proc/sys/kernel/tainted
@@ -742,18 +811,7 @@ EOF
ip netns exec "$ns1" nft flush ruleset
if [ "$tainted_then" -ne 0 ];then
return
fi
read tainted_now < /proc/sys/kernel/tainted
if [ "$tainted_now" -eq 0 ];then
echo "PASS: queue program exiting while packets queued"
else
echo "TAINT: queue program exiting while packets queued"
dmesg
ret=1
fi
check_tainted "queue program exiting while packets queued"
}
ip netns exec "$nsrouter" sysctl net.ipv6.conf.all.forwarding=1 > /dev/null
@@ -799,6 +857,7 @@ test_sctp_forward
test_sctp_output
test_udp_nat_race
test_udp_gro_ct
test_queue_stress
# should be last, adds vrf device in ns1 and changes routes
test_icmp_vrf

View File

@@ -0,0 +1,197 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# author: Andrea Mayer <andrea.mayer@uniroma2.it>
# This test verifies that the seg6 lwtunnel does not share the dst_cache
# between the input (forwarding) and output (locally generated) paths.
#
# A shared dst_cache allows a forwarded packet to populate the cache and a
# subsequent locally generated packet to silently reuse that entry, bypassing
# its own route lookup. To expose this, the SID is made reachable only for
# forwarded traffic (via an ip rule matching iif) and blackholed for everything
# else. A local ping on ns_router must always hit the blackhole;
# if it succeeds after a forwarded packet has populated the
# cache, the bug is confirmed.
#
# Both forwarded and local packets are pinned to the same CPU with taskset,
# since dst_cache is per-cpu.
#
#
# +--------------------+ +--------------------+
# | ns_src | | ns_dst |
# | | | |
# | veth-s0 | | veth-d0 |
# | fd00::1/64 | | fd01::2/64 |
# +-------+------------+ +----------+---------+
# | |
# | +--------------------+ |
# | | ns_router | |
# | | | |
# +------------+ veth-r0 veth-r1 +--------------+
# | fd00::2 fd01::1 |
# +--------------------+
#
#
# ns_router: encap (main table)
# +---------+---------------------------------------+
# | dst | action |
# +---------+---------------------------------------+
# | cafe::1 | encap seg6 mode encap segs fc00::100 |
# +---------+---------------------------------------+
#
# ns_router: post-encap SID resolution
# +-------+------------+----------------------------+
# | table | dst | action |
# +-------+------------+----------------------------+
# | 100 | fc00::100 | via fd01::2 dev veth-r1 |
# +-------+------------+----------------------------+
# | main | fc00::100 | blackhole |
# +-------+------------+----------------------------+
#
# ns_router: ip rule
# +------------------+------------------------------+
# | match | action |
# +------------------+------------------------------+
# | iif veth-r0 | lookup 100 |
# +------------------+------------------------------+
#
# ns_dst: SRv6 decap (main table)
# +--------------+----------------------------------+
# | SID | action |
# +--------------+----------------------------------+
# | fc00::100 | End.DT6 table 255 (local) |
# +--------------+----------------------------------+
source lib.sh
readonly SID="fc00::100"
readonly DEST="cafe::1"
readonly SRC_MAC="02:00:00:00:00:01"
readonly RTR_R0_MAC="02:00:00:00:00:02"
readonly RTR_R1_MAC="02:00:00:00:00:03"
readonly DST_MAC="02:00:00:00:00:04"
cleanup()
{
cleanup_ns "${NS_SRC}" "${NS_RTR}" "${NS_DST}"
}
check_prerequisites()
{
if ! command -v ip &>/dev/null; then
echo "SKIP: ip tool not found"
exit "${ksft_skip}"
fi
if ! command -v ping &>/dev/null; then
echo "SKIP: ping not found"
exit "${ksft_skip}"
fi
if ! command -v sysctl &>/dev/null; then
echo "SKIP: sysctl not found"
exit "${ksft_skip}"
fi
if ! command -v taskset &>/dev/null; then
echo "SKIP: taskset not found"
exit "${ksft_skip}"
fi
}
setup()
{
setup_ns NS_SRC NS_RTR NS_DST
ip link add veth-s0 netns "${NS_SRC}" type veth \
peer name veth-r0 netns "${NS_RTR}"
ip link add veth-r1 netns "${NS_RTR}" type veth \
peer name veth-d0 netns "${NS_DST}"
ip -n "${NS_SRC}" link set veth-s0 address "${SRC_MAC}"
ip -n "${NS_RTR}" link set veth-r0 address "${RTR_R0_MAC}"
ip -n "${NS_RTR}" link set veth-r1 address "${RTR_R1_MAC}"
ip -n "${NS_DST}" link set veth-d0 address "${DST_MAC}"
# ns_src
ip -n "${NS_SRC}" link set veth-s0 up
ip -n "${NS_SRC}" addr add fd00::1/64 dev veth-s0 nodad
ip -n "${NS_SRC}" -6 route add "${DEST}"/128 via fd00::2
# ns_router
ip -n "${NS_RTR}" link set veth-r0 up
ip -n "${NS_RTR}" addr add fd00::2/64 dev veth-r0 nodad
ip -n "${NS_RTR}" link set veth-r1 up
ip -n "${NS_RTR}" addr add fd01::1/64 dev veth-r1 nodad
ip netns exec "${NS_RTR}" sysctl -qw net.ipv6.conf.all.forwarding=1
ip -n "${NS_RTR}" -6 route add "${DEST}"/128 \
encap seg6 mode encap segs "${SID}" dev veth-r0
ip -n "${NS_RTR}" -6 route add "${SID}"/128 table 100 \
via fd01::2 dev veth-r1
ip -n "${NS_RTR}" -6 route add blackhole "${SID}"/128
ip -n "${NS_RTR}" -6 rule add iif veth-r0 lookup 100
# ns_dst
ip -n "${NS_DST}" link set veth-d0 up
ip -n "${NS_DST}" addr add fd01::2/64 dev veth-d0 nodad
ip -n "${NS_DST}" addr add "${DEST}"/128 dev lo nodad
ip -n "${NS_DST}" -6 route add "${SID}"/128 \
encap seg6local action End.DT6 table 255 dev veth-d0
ip -n "${NS_DST}" -6 route add fd00::/64 via fd01::1
# static neighbors
ip -n "${NS_SRC}" -6 neigh add fd00::2 dev veth-s0 \
lladdr "${RTR_R0_MAC}" nud permanent
ip -n "${NS_RTR}" -6 neigh add fd00::1 dev veth-r0 \
lladdr "${SRC_MAC}" nud permanent
ip -n "${NS_RTR}" -6 neigh add fd01::2 dev veth-r1 \
lladdr "${DST_MAC}" nud permanent
ip -n "${NS_DST}" -6 neigh add fd01::1 dev veth-d0 \
lladdr "${RTR_R1_MAC}" nud permanent
}
test_cache_isolation()
{
RET=0
# local ping with empty cache: must fail (SID is blackholed)
if ip netns exec "${NS_RTR}" taskset -c 0 \
ping -c 1 -W 2 "${DEST}" &>/dev/null; then
echo "SKIP: local ping succeeded, topology broken"
exit "${ksft_skip}"
fi
# forward from ns_src to populate the input cache
if ! ip netns exec "${NS_SRC}" taskset -c 0 \
ping -c 1 -W 2 "${DEST}" &>/dev/null; then
echo "SKIP: forwarded ping failed, topology broken"
exit "${ksft_skip}"
fi
# local ping again: must still fail; if the output path reuses
# the input cache, it bypasses the blackhole and the ping succeeds
if ip netns exec "${NS_RTR}" taskset -c 0 \
ping -c 1 -W 2 "${DEST}" &>/dev/null; then
echo "FAIL: output path used dst cached by input path"
RET="${ksft_fail}"
else
echo "PASS: output path dst_cache is independent"
fi
return "${RET}"
}
if [ "$(id -u)" -ne 0 ]; then
echo "SKIP: Need root privileges"
exit "${ksft_skip}"
fi
trap cleanup EXIT
check_prerequisites
setup
test_cache_isolation
exit "${RET}"

View File

@@ -344,7 +344,9 @@ void send_buf(int fd, const void *buf, size_t len, int flags,
ret = send(fd, buf + nwritten, len - nwritten, flags);
timeout_check("send");
if (ret == 0 || (ret < 0 && errno != EINTR))
if (ret < 0 && errno == EINTR)
continue;
if (ret <= 0)
break;
nwritten += ret;
@@ -396,7 +398,9 @@ void recv_buf(int fd, void *buf, size_t len, int flags, ssize_t expected_ret)
ret = recv(fd, buf + nread, len - nread, flags);
timeout_check("recv");
if (ret == 0 || (ret < 0 && errno != EINTR))
if (ret < 0 && errno == EINTR)
continue;
if (ret <= 0)
break;
nread += ret;