mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
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:
@@ -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>,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
struct nf_ct_timeout {
|
||||
__u16 l3num;
|
||||
const struct nf_conntrack_l4proto *l4proto;
|
||||
struct rcu_head rcu;
|
||||
char data[];
|
||||
};
|
||||
|
||||
|
||||
@@ -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 */
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 ") \
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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]),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 ||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
197
tools/testing/selftests/net/srv6_iptunnel_cache.sh
Executable file
197
tools/testing/selftests/net/srv6_iptunnel_cache.sh
Executable 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}"
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user