mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 01:11:51 -04:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Merge in late fixes in preparation for the net-next PR. Conflicts: drivers/dpll/dpll_core.c drivers/dpll/dpll_netlink.c33f016b23a("dpll: fix NULL deref in dpll_device_ops() during teardown race")b1d0c41208("dpll: add STATE_CONNECTED_OVERRIDE pin capability") https://lore.kernel.org/aoR9YYY2P5--3x0N@sirena.org.uk https://lore.kernel.org/aoR9VmKllVGwmQn_@sirena.org.uk No adjacent changes. Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -876,14 +876,12 @@ int
|
||||
dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin,
|
||||
const struct dpll_pin_ops *ops, void *priv)
|
||||
{
|
||||
const struct dpll_device_ops *dev_ops;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(!ops) ||
|
||||
WARN_ON(!ops->state_on_dpll_get) ||
|
||||
WARN_ON(!ops->direction_get) ||
|
||||
WARN_ON(ops->measured_freq_get &&
|
||||
(!dpll_device_ops(dpll)->freq_monitor_get ||
|
||||
!dpll_device_ops(dpll)->freq_monitor_set)) ||
|
||||
WARN_ON(ops->supported_ffo && !ops->ffo_get) ||
|
||||
WARN_ON((pin->prop.capabilities &
|
||||
DPLL_PIN_CAPABILITIES_STATE_CONNECTED_OVERRIDE) &&
|
||||
@@ -893,6 +891,14 @@ dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin,
|
||||
|
||||
mutex_lock(&dpll_lock);
|
||||
|
||||
dev_ops = dpll_device_ops(dpll);
|
||||
if (WARN_ON(ops->measured_freq_get &&
|
||||
(!dev_ops || !dev_ops->freq_monitor_get ||
|
||||
!dev_ops->freq_monitor_set))) {
|
||||
ret = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* For pins identified via firmware (pin->fwnode), allow registration
|
||||
* even if the pin's (module, clock_id) differs from the target DPLL.
|
||||
@@ -1085,12 +1091,8 @@ EXPORT_SYMBOL_GPL(dpll_pin_ref_sync_pair_add);
|
||||
static struct dpll_device_registration *
|
||||
dpll_device_registration_first(struct dpll_device *dpll)
|
||||
{
|
||||
struct dpll_device_registration *reg;
|
||||
|
||||
reg = list_first_entry_or_null((struct list_head *)&dpll->registration_list,
|
||||
struct dpll_device_registration, list);
|
||||
WARN_ON(!reg);
|
||||
return reg;
|
||||
return list_first_entry_or_null((struct list_head *)&dpll->registration_list,
|
||||
struct dpll_device_registration, list);
|
||||
}
|
||||
|
||||
void *dpll_priv(struct dpll_device *dpll)
|
||||
@@ -1098,6 +1100,8 @@ void *dpll_priv(struct dpll_device *dpll)
|
||||
struct dpll_device_registration *reg;
|
||||
|
||||
reg = dpll_device_registration_first(dpll);
|
||||
if (!reg)
|
||||
return NULL;
|
||||
return reg->priv;
|
||||
}
|
||||
|
||||
@@ -1106,6 +1110,8 @@ const struct dpll_device_ops *dpll_device_ops(struct dpll_device *dpll)
|
||||
struct dpll_device_registration *reg;
|
||||
|
||||
reg = dpll_device_registration_first(dpll);
|
||||
if (!reg)
|
||||
return NULL;
|
||||
return reg->ops;
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +66,22 @@ static bool dpll_pin_available(struct dpll_pin *pin)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool dpll_device_registered(struct dpll_device *dpll)
|
||||
{
|
||||
return dpll_device_ops(dpll);
|
||||
}
|
||||
|
||||
static struct dpll_pin_ref *dpll_pin_first_registered_ref(struct dpll_pin *pin)
|
||||
{
|
||||
struct dpll_pin_ref *ref;
|
||||
unsigned long i;
|
||||
|
||||
xa_for_each(&pin->dpll_refs, i, ref)
|
||||
if (dpll_device_registered(ref->dpll))
|
||||
return ref;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* dpll_msg_add_pin_handle - attach pin handle attribute to a given message
|
||||
* @msg: pointer to sk_buff message to attach a pin handle
|
||||
@@ -656,6 +672,8 @@ dpll_msg_add_pin_dplls(struct sk_buff *msg, struct dpll_pin *pin,
|
||||
int ret;
|
||||
|
||||
xa_for_each(&pin->dpll_refs, index, ref) {
|
||||
if (!dpll_device_registered(ref->dpll))
|
||||
continue;
|
||||
attr = nla_nest_start(msg, DPLL_A_PIN_PARENT_DEVICE);
|
||||
if (!attr)
|
||||
return -EMSGSIZE;
|
||||
@@ -700,9 +718,10 @@ dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin,
|
||||
int ret;
|
||||
|
||||
ref = dpll_pin_own_dpll_ref_first(pin);
|
||||
if (!ref || !dpll_device_registered(ref->dpll))
|
||||
ref = dpll_pin_first_registered_ref(pin);
|
||||
if (!ref)
|
||||
ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
|
||||
ASSERT_NOT_NULL(ref);
|
||||
return -ENODEV;
|
||||
|
||||
ret = dpll_msg_add_pin_handle(msg, pin);
|
||||
if (ret)
|
||||
@@ -1090,7 +1109,7 @@ dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
|
||||
}
|
||||
|
||||
ref = dpll_pin_own_dpll_ref_first(pin);
|
||||
if (!ref) {
|
||||
if (!ref || !dpll_device_registered(ref->dpll)) {
|
||||
NL_SET_ERR_MSG(extack, "pin owner dpll not found");
|
||||
return -ENODEV;
|
||||
}
|
||||
@@ -1136,7 +1155,7 @@ dpll_pin_esync_set(struct dpll_pin *pin, struct nlattr *a,
|
||||
int ret, i;
|
||||
|
||||
ref = dpll_pin_own_dpll_ref_first(pin);
|
||||
if (!ref) {
|
||||
if (!ref || !dpll_device_registered(ref->dpll)) {
|
||||
NL_SET_ERR_MSG(extack, "pin owner dpll not found");
|
||||
return -ENODEV;
|
||||
}
|
||||
@@ -1201,7 +1220,7 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
|
||||
return -EINVAL;
|
||||
}
|
||||
ref = dpll_pin_own_dpll_ref_first(pin);
|
||||
if (!ref) {
|
||||
if (!ref || !dpll_device_registered(ref->dpll)) {
|
||||
NL_SET_ERR_MSG(extack, "pin owner dpll not found");
|
||||
return -ENODEV;
|
||||
}
|
||||
@@ -1416,7 +1435,7 @@ dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr,
|
||||
}
|
||||
|
||||
ref = dpll_pin_own_dpll_ref_first(pin);
|
||||
if (!ref) {
|
||||
if (!ref || !dpll_device_registered(ref->dpll)) {
|
||||
NL_SET_ERR_MSG(extack, "pin owner dpll not found");
|
||||
return -ENODEV;
|
||||
}
|
||||
@@ -1468,7 +1487,7 @@ dpll_pin_parent_device_set(struct dpll_pin *pin, struct nlattr *parent_nest,
|
||||
return -EINVAL;
|
||||
}
|
||||
pdpll_idx = nla_get_u32(tb[DPLL_A_PIN_PARENT_ID]);
|
||||
dpll = xa_load(&dpll_device_xa, pdpll_idx);
|
||||
dpll = dpll_device_get_by_id(pdpll_idx);
|
||||
if (!dpll) {
|
||||
NL_SET_ERR_MSG(extack, "parent device not found");
|
||||
return -EINVAL;
|
||||
@@ -1760,6 +1779,10 @@ int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
ret = dpll_cmd_pin_get_one(skb, pin, cb->extack);
|
||||
if (ret) {
|
||||
genlmsg_cancel(skb, hdr);
|
||||
if (ret == -ENODEV) {
|
||||
ret = 0;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
genlmsg_end(skb, hdr);
|
||||
|
||||
@@ -220,7 +220,7 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
|
||||
struct bonding *bond = netdev_priv(bond_dev);
|
||||
struct bond_opt_value newval;
|
||||
int miimon = 0;
|
||||
int err;
|
||||
int err = 0;
|
||||
|
||||
if (!data)
|
||||
return 0;
|
||||
|
||||
@@ -2219,7 +2219,7 @@ int b53_fdb_dump(struct dsa_switch *ds, int port,
|
||||
|
||||
mutex_unlock(&priv->arl_mutex);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(b53_fdb_dump);
|
||||
|
||||
|
||||
@@ -305,13 +305,16 @@ static bool mv88e6352_pcs_link_check(struct marvell_c22_pcs *mpcs)
|
||||
struct mv88e6xxx_port *port = mpcs->port;
|
||||
struct mv88e6xxx_chip *chip = port->chip;
|
||||
u8 cmode;
|
||||
int err;
|
||||
|
||||
/* Port 4 can be in auto-media mode. Check that the port is
|
||||
* associated with the mpcs.
|
||||
*/
|
||||
mv88e6xxx_reg_lock(chip);
|
||||
chip->info->ops->port_get_cmode(chip, port->port, &cmode);
|
||||
err = chip->info->ops->port_get_cmode(chip, port->port, &cmode);
|
||||
mv88e6xxx_reg_unlock(chip);
|
||||
if (err)
|
||||
return false;
|
||||
|
||||
return cmode == MV88E6XXX_PORT_STS_CMODE_100BASEX ||
|
||||
cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
|
||||
|
||||
@@ -321,7 +321,7 @@ void rtl83xx_reset_assert(struct realtek_priv *priv)
|
||||
"Failed to assert the switch reset control: %pe\n",
|
||||
ERR_PTR(ret));
|
||||
|
||||
gpiod_set_value(priv->reset, true);
|
||||
gpiod_set_value_cansleep(priv->reset, true);
|
||||
}
|
||||
|
||||
void rtl83xx_reset_deassert(struct realtek_priv *priv)
|
||||
@@ -334,7 +334,7 @@ void rtl83xx_reset_deassert(struct realtek_priv *priv)
|
||||
"Failed to deassert the switch reset control: %pe\n",
|
||||
ERR_PTR(ret));
|
||||
|
||||
gpiod_set_value(priv->reset, false);
|
||||
gpiod_set_value_cansleep(priv->reset, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -261,8 +261,7 @@ static int hinic3_tx_csum(struct hinic3_txq *txq, struct hinic3_sq_task *task,
|
||||
((struct udphdr *)skb_transport_header(skb))->dest !=
|
||||
VXLAN_OFFLOAD_PORT_LE) {
|
||||
/* Unsupported tunnel packet, disable csum offload */
|
||||
skb_checksum_help(skb);
|
||||
return 0;
|
||||
return skb_checksum_help(skb);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -412,6 +411,10 @@ static u32 hinic3_tx_offload(struct sk_buff *skb, struct hinic3_sq_task *task,
|
||||
offload |= HINIC3_TX_OFFLOAD_TSO;
|
||||
} else {
|
||||
tso_cs_en = hinic3_tx_csum(txq, task, skb);
|
||||
if (tso_cs_en < 0) {
|
||||
offload = HINIC3_TX_OFFLOAD_INVALID;
|
||||
return offload;
|
||||
}
|
||||
if (tso_cs_en)
|
||||
offload |= HINIC3_TX_OFFLOAD_CSUM;
|
||||
}
|
||||
@@ -545,6 +548,7 @@ static netdev_tx_t hinic3_send_one_skb(struct sk_buff *skb,
|
||||
skb->len = MIN_SKB_LEN;
|
||||
}
|
||||
|
||||
offload = hinic3_tx_offload(skb, &task, &queue_info, txq);
|
||||
num_sge = skb_shinfo(skb)->nr_frags + 1;
|
||||
/* assume normal wqe format + 1 wqebb for task info */
|
||||
wqebb_cnt = num_sge + 1;
|
||||
@@ -560,7 +564,6 @@ static netdev_tx_t hinic3_send_one_skb(struct sk_buff *skb,
|
||||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
offload = hinic3_tx_offload(skb, &task, &queue_info, txq);
|
||||
if (unlikely(offload == HINIC3_TX_OFFLOAD_INVALID)) {
|
||||
goto err_drop_pkt;
|
||||
} else if (!offload) {
|
||||
|
||||
@@ -35,6 +35,7 @@ int mal_register_commac(struct mal_instance *mal, struct mal_commac *commac)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
netdev_lock(mal->napi.dev);
|
||||
spin_lock_irqsave(&mal->lock, flags);
|
||||
|
||||
MAL_DBG(mal, "reg(%08x, %08x)" NL,
|
||||
@@ -44,18 +45,20 @@ int mal_register_commac(struct mal_instance *mal, struct mal_commac *commac)
|
||||
if ((mal->tx_chan_mask & commac->tx_chan_mask) ||
|
||||
(mal->rx_chan_mask & commac->rx_chan_mask)) {
|
||||
spin_unlock_irqrestore(&mal->lock, flags);
|
||||
netdev_unlock(mal->napi.dev);
|
||||
printk(KERN_WARNING "mal%d: COMMAC channels conflict!\n",
|
||||
mal->index);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (list_empty(&mal->list))
|
||||
napi_enable(&mal->napi);
|
||||
napi_enable_locked(&mal->napi);
|
||||
mal->tx_chan_mask |= commac->tx_chan_mask;
|
||||
mal->rx_chan_mask |= commac->rx_chan_mask;
|
||||
list_add(&commac->list, &mal->list);
|
||||
|
||||
spin_unlock_irqrestore(&mal->lock, flags);
|
||||
netdev_unlock(mal->napi.dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -64,7 +67,9 @@ void mal_unregister_commac(struct mal_instance *mal,
|
||||
struct mal_commac *commac)
|
||||
{
|
||||
unsigned long flags;
|
||||
bool disable_napi;
|
||||
|
||||
netdev_lock(mal->napi.dev);
|
||||
spin_lock_irqsave(&mal->lock, flags);
|
||||
|
||||
MAL_DBG(mal, "unreg(%08x, %08x)" NL,
|
||||
@@ -73,10 +78,12 @@ void mal_unregister_commac(struct mal_instance *mal,
|
||||
mal->tx_chan_mask &= ~commac->tx_chan_mask;
|
||||
mal->rx_chan_mask &= ~commac->rx_chan_mask;
|
||||
list_del_init(&commac->list);
|
||||
if (list_empty(&mal->list))
|
||||
napi_disable(&mal->napi);
|
||||
disable_napi = list_empty(&mal->list);
|
||||
|
||||
spin_unlock_irqrestore(&mal->lock, flags);
|
||||
if (disable_napi)
|
||||
napi_disable_locked(&mal->napi);
|
||||
netdev_unlock(mal->napi.dev);
|
||||
}
|
||||
|
||||
int mal_set_rcbs(struct mal_instance *mal, int channel, unsigned long size)
|
||||
|
||||
@@ -1890,27 +1890,18 @@ static int ice_devlink_nvm_snapshot(struct devlink *devlink,
|
||||
*/
|
||||
for (i = 0; i < num_blks; i++) {
|
||||
u32 read_sz = min_t(u32, ICE_DEVLINK_READ_BLK_SIZE, left);
|
||||
|
||||
status = ice_acquire_nvm(hw, ICE_RES_READ);
|
||||
if (status) {
|
||||
dev_dbg(dev, "ice_acquire_nvm failed, err %d aq_err %d\n",
|
||||
status, hw->adminq.sq_last_status);
|
||||
NL_SET_ERR_MSG_MOD(extack, "Failed to acquire NVM semaphore");
|
||||
vfree(nvm_data);
|
||||
return -EIO;
|
||||
}
|
||||
enum libie_aq_err read_aq_err = LIBIE_AQ_RC_OK;
|
||||
|
||||
status = ice_read_flat_nvm(hw, i * ICE_DEVLINK_READ_BLK_SIZE,
|
||||
&read_sz, tmp, read_shadow_ram);
|
||||
&read_sz, tmp, read_shadow_ram,
|
||||
&read_aq_err);
|
||||
if (status) {
|
||||
dev_dbg(dev, "ice_read_flat_nvm failed after reading %u bytes, err %d aq_err %d\n",
|
||||
read_sz, status, hw->adminq.sq_last_status);
|
||||
read_sz, status, read_aq_err);
|
||||
NL_SET_ERR_MSG_MOD(extack, "Failed to read NVM contents");
|
||||
ice_release_nvm(hw);
|
||||
vfree(nvm_data);
|
||||
return -EIO;
|
||||
}
|
||||
ice_release_nvm(hw);
|
||||
|
||||
tmp += read_sz;
|
||||
left -= read_sz;
|
||||
@@ -1943,6 +1934,7 @@ static int ice_devlink_nvm_read(struct devlink *devlink,
|
||||
struct netlink_ext_ack *extack,
|
||||
u64 offset, u32 size, u8 *data)
|
||||
{
|
||||
enum libie_aq_err read_aq_err = LIBIE_AQ_RC_OK;
|
||||
struct ice_pf *pf = devlink_priv(devlink);
|
||||
struct device *dev = ice_pf_to_dev(pf);
|
||||
struct ice_hw *hw = &pf->hw;
|
||||
@@ -1966,24 +1958,14 @@ static int ice_devlink_nvm_read(struct devlink *devlink,
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
status = ice_acquire_nvm(hw, ICE_RES_READ);
|
||||
if (status) {
|
||||
dev_dbg(dev, "ice_acquire_nvm failed, err %d aq_err %d\n",
|
||||
status, hw->adminq.sq_last_status);
|
||||
NL_SET_ERR_MSG_MOD(extack, "Failed to acquire NVM semaphore");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
status = ice_read_flat_nvm(hw, (u32)offset, &size, data,
|
||||
read_shadow_ram);
|
||||
read_shadow_ram, &read_aq_err);
|
||||
if (status) {
|
||||
dev_dbg(dev, "ice_read_flat_nvm failed after reading %u bytes, err %d aq_err %d\n",
|
||||
size, status, hw->adminq.sq_last_status);
|
||||
size, status, read_aq_err);
|
||||
NL_SET_ERR_MSG_MOD(extack, "Failed to read NVM contents");
|
||||
ice_release_nvm(hw);
|
||||
return -EIO;
|
||||
}
|
||||
ice_release_nvm(hw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -853,6 +853,7 @@ static int
|
||||
ice_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,
|
||||
u8 *bytes)
|
||||
{
|
||||
enum libie_aq_err read_aq_err = LIBIE_AQ_RC_OK;
|
||||
struct ice_pf *pf = ice_netdev_to_pf(netdev);
|
||||
struct ice_hw *hw = &pf->hw;
|
||||
struct device *dev;
|
||||
@@ -869,24 +870,15 @@ ice_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = ice_acquire_nvm(hw, ICE_RES_READ);
|
||||
ret = ice_read_flat_nvm(hw, eeprom->offset, &eeprom->len, buf,
|
||||
false, &read_aq_err);
|
||||
if (ret) {
|
||||
dev_err(dev, "ice_acquire_nvm failed, err %d aq_err %s\n",
|
||||
ret, libie_aq_str(hw->adminq.sq_last_status));
|
||||
dev_err(dev, "ice_read_flat_nvm failed, err %d aq_err %s\n",
|
||||
ret, libie_aq_str(read_aq_err));
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ice_read_flat_nvm(hw, eeprom->offset, &eeprom->len, buf,
|
||||
false);
|
||||
if (ret) {
|
||||
dev_err(dev, "ice_read_flat_nvm failed, err %d aq_err %s\n",
|
||||
ret, libie_aq_str(hw->adminq.sq_last_status));
|
||||
goto release;
|
||||
}
|
||||
|
||||
memcpy(bytes, buf, eeprom->len);
|
||||
release:
|
||||
ice_release_nvm(hw);
|
||||
out:
|
||||
kfree(buf);
|
||||
return ret;
|
||||
|
||||
@@ -2871,6 +2871,9 @@ int ice_vsi_release(struct ice_vsi *vsi)
|
||||
return -ENODEV;
|
||||
pf = vsi->back;
|
||||
|
||||
if (ice_is_vsi_dflt_vsi(vsi))
|
||||
ice_clear_dflt_vsi(vsi);
|
||||
|
||||
if (test_bit(ICE_FLAG_RSS_ENA, pf->flags))
|
||||
ice_rss_clean(vsi);
|
||||
|
||||
|
||||
@@ -53,17 +53,27 @@ int ice_aq_read_nvm(struct ice_hw *hw, u16 module_typeid, u32 offset,
|
||||
* @length: (in) number of bytes to read; (out) number of bytes actually read
|
||||
* @data: buffer to return data in (sized to fit the specified length)
|
||||
* @read_shadow_ram: if true, read from shadow RAM instead of NVM
|
||||
* @read_aq_err: if non-NULL, receives the AQ error status of the failing read
|
||||
*
|
||||
* Reads a portion of the NVM, as a flat memory space. This function correctly
|
||||
* breaks read requests across Shadow RAM sectors and ensures that no single
|
||||
* read request exceeds the maximum 4KB read for a single AdminQ command.
|
||||
*
|
||||
* FW caps the read lock at a maximum of 3000ms, so a read spanning multiple
|
||||
* 4KB sectors cannot be done under a single lock without FW reclaiming it
|
||||
* mid-read. The NVM lock is therefore acquired and released around each AQ
|
||||
* read, so this function must be called without the lock held.
|
||||
*
|
||||
* Since ice_release_nvm() issues an AQ command that overwrites
|
||||
* hw->adminq.sq_last_status, callers that need the failing read's AQ error
|
||||
* must use @read_aq_err rather than inspecting sq_last_status afterwards.
|
||||
*
|
||||
* Returns a status code on failure. Note that the data pointer may be
|
||||
* partially updated if some reads succeed before a failure.
|
||||
*/
|
||||
int
|
||||
ice_read_flat_nvm(struct ice_hw *hw, u32 offset, u32 *length, u8 *data,
|
||||
bool read_shadow_ram)
|
||||
bool read_shadow_ram, enum libie_aq_err *read_aq_err)
|
||||
{
|
||||
u32 inlen = *length;
|
||||
u32 bytes_read = 0;
|
||||
@@ -92,12 +102,30 @@ ice_read_flat_nvm(struct ice_hw *hw, u32 offset, u32 *length, u8 *data,
|
||||
|
||||
last_cmd = !(bytes_read + read_size < inlen);
|
||||
|
||||
status = ice_acquire_nvm(hw, ICE_RES_READ);
|
||||
if (status) {
|
||||
ice_debug(hw, ICE_DBG_NVM, "Failed to acquire NVM lock, err %d aq_err %s\n",
|
||||
status, libie_aq_str(hw->adminq.sq_last_status));
|
||||
break;
|
||||
}
|
||||
|
||||
status = ice_aq_read_nvm(hw, ICE_AQC_NVM_START_POINT,
|
||||
offset, read_size,
|
||||
data + bytes_read, last_cmd,
|
||||
read_shadow_ram, NULL);
|
||||
if (status)
|
||||
if (status) {
|
||||
/* Capture the read's AQ error before ice_release_nvm()
|
||||
* issues its own AQ command and overwrites
|
||||
* sq_last_status.
|
||||
*/
|
||||
if (read_aq_err)
|
||||
*read_aq_err = hw->adminq.sq_last_status;
|
||||
|
||||
ice_release_nvm(hw);
|
||||
break;
|
||||
}
|
||||
|
||||
ice_release_nvm(hw);
|
||||
|
||||
bytes_read += read_size;
|
||||
offset += read_size;
|
||||
@@ -177,14 +205,19 @@ int ice_aq_erase_nvm(struct ice_hw *hw, u16 module_typeid, struct ice_sq_cd *cd)
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_read_sr_word_aq - Reads Shadow RAM via AQ
|
||||
* ice_read_sr_word - Reads Shadow RAM word
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
|
||||
* @data: word read from the Shadow RAM
|
||||
*
|
||||
* Reads one 16 bit word from the Shadow RAM using ice_read_flat_nvm.
|
||||
*
|
||||
* The NVM lock is acquired and released internally by ice_read_flat_nvm()
|
||||
* around the FW read, so this function must be called without the lock held.
|
||||
*
|
||||
* Return: zero on success, or a negative error code on failure.
|
||||
*/
|
||||
static int ice_read_sr_word_aq(struct ice_hw *hw, u16 offset, u16 *data)
|
||||
int ice_read_sr_word(struct ice_hw *hw, u16 offset, u16 *data)
|
||||
{
|
||||
u32 bytes = sizeof(u16);
|
||||
__le16 data_local;
|
||||
@@ -194,7 +227,7 @@ static int ice_read_sr_word_aq(struct ice_hw *hw, u16 offset, u16 *data)
|
||||
* Shadow RAM sector restrictions necessary when reading from the NVM.
|
||||
*/
|
||||
status = ice_read_flat_nvm(hw, offset * sizeof(u16), &bytes,
|
||||
(__force u8 *)&data_local, true);
|
||||
(__force u8 *)&data_local, true, NULL);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
@@ -330,13 +363,8 @@ ice_read_flash_module(struct ice_hw *hw, enum ice_bank_select bank, u16 module,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
status = ice_acquire_nvm(hw, ICE_RES_READ);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = ice_read_flat_nvm(hw, start + offset, &length, data, false);
|
||||
|
||||
ice_release_nvm(hw);
|
||||
status = ice_read_flat_nvm(hw, start + offset, &length, data, false,
|
||||
NULL);
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -418,27 +446,6 @@ ice_read_netlist_module(struct ice_hw *hw, enum ice_bank_select bank, u32 offset
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_read_sr_word - Reads Shadow RAM word and acquire NVM if necessary
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
|
||||
* @data: word read from the Shadow RAM
|
||||
*
|
||||
* Reads one 16 bit word from the Shadow RAM using the ice_read_sr_word_aq.
|
||||
*/
|
||||
int ice_read_sr_word(struct ice_hw *hw, u16 offset, u16 *data)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = ice_acquire_nvm(hw, ICE_RES_READ);
|
||||
if (!status) {
|
||||
status = ice_read_sr_word_aq(hw, offset, data);
|
||||
ice_release_nvm(hw);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_get_pfa_module_tlv - Reads sub module TLV from NVM PFA
|
||||
* @hw: pointer to hardware structure
|
||||
@@ -856,20 +863,18 @@ int ice_get_inactive_netlist_ver(struct ice_hw *hw, struct ice_netlist_info *net
|
||||
static int ice_discover_flash_size(struct ice_hw *hw)
|
||||
{
|
||||
u32 min_size = 0, max_size = ICE_AQC_NVM_MAX_OFFSET + 1;
|
||||
int status;
|
||||
|
||||
status = ice_acquire_nvm(hw, ICE_RES_READ);
|
||||
if (status)
|
||||
return status;
|
||||
int status = 0;
|
||||
|
||||
while ((max_size - min_size) > 1) {
|
||||
enum libie_aq_err read_aq_err = LIBIE_AQ_RC_OK;
|
||||
u32 offset = (max_size + min_size) / 2;
|
||||
u32 len = 1;
|
||||
u8 data;
|
||||
|
||||
status = ice_read_flat_nvm(hw, offset, &len, &data, false);
|
||||
status = ice_read_flat_nvm(hw, offset, &len, &data, false,
|
||||
&read_aq_err);
|
||||
if (status == -EIO &&
|
||||
hw->adminq.sq_last_status == LIBIE_AQ_RC_EINVAL) {
|
||||
read_aq_err == LIBIE_AQ_RC_EINVAL) {
|
||||
ice_debug(hw, ICE_DBG_NVM, "%s: New upper bound of %u bytes\n",
|
||||
__func__, offset);
|
||||
status = 0;
|
||||
@@ -880,7 +885,7 @@ static int ice_discover_flash_size(struct ice_hw *hw)
|
||||
min_size = offset;
|
||||
} else {
|
||||
/* an unexpected error occurred */
|
||||
goto err_read_flat_nvm;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -888,9 +893,6 @@ static int ice_discover_flash_size(struct ice_hw *hw)
|
||||
|
||||
hw->flash.flash_size = max_size;
|
||||
|
||||
err_read_flat_nvm:
|
||||
ice_release_nvm(hw);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ int ice_aq_read_nvm(struct ice_hw *hw, u16 module_typeid, u32 offset,
|
||||
bool read_shadow_ram, struct ice_sq_cd *cd);
|
||||
int
|
||||
ice_read_flat_nvm(struct ice_hw *hw, u32 offset, u32 *length, u8 *data,
|
||||
bool read_shadow_ram);
|
||||
bool read_shadow_ram, enum libie_aq_err *read_aq_err);
|
||||
int
|
||||
ice_get_pfa_module_tlv(struct ice_hw *hw, u16 *module_tlv, u16 *module_tlv_len,
|
||||
u16 module_type);
|
||||
|
||||
@@ -4808,15 +4808,12 @@ static int ice_ptp_prep_phy_adj_ll_e810(struct ice_hw *hw, s32 adj)
|
||||
!FIELD_GET(REG_LL_PROXY_H_EXEC, val),
|
||||
10, REG_LL_PROXY_H_TIMEOUT_US, false, hw,
|
||||
REG_LL_PROXY_H);
|
||||
if (err) {
|
||||
ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY timer adjustment using low latency interface\n");
|
||||
spin_unlock_irq(¶ms->atqbal_wq.lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
spin_unlock_irq(¶ms->atqbal_wq.lock);
|
||||
|
||||
return 0;
|
||||
if (err)
|
||||
ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY timer adjustment using low latency interface\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4837,8 +4834,12 @@ static int ice_ptp_prep_phy_adj_e810(struct ice_hw *hw, s32 adj)
|
||||
u8 tmr_idx;
|
||||
int err;
|
||||
|
||||
if (hw->dev_caps.ts_dev_info.ll_phy_tmr_update)
|
||||
return ice_ptp_prep_phy_adj_ll_e810(hw, adj);
|
||||
if (hw->dev_caps.ts_dev_info.ll_phy_tmr_update) {
|
||||
err = ice_ptp_prep_phy_adj_ll_e810(hw, adj);
|
||||
if (err != -ETIMEDOUT)
|
||||
return err;
|
||||
ice_debug(hw, ICE_DBG_PTP, "LL adj timed out, falling back to SBQ\n");
|
||||
}
|
||||
|
||||
tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
|
||||
|
||||
@@ -4901,15 +4902,12 @@ static int ice_ptp_prep_phy_incval_ll_e810(struct ice_hw *hw, u64 incval)
|
||||
!FIELD_GET(REG_LL_PROXY_H_EXEC, val),
|
||||
10, REG_LL_PROXY_H_TIMEOUT_US, false, hw,
|
||||
REG_LL_PROXY_H);
|
||||
if (err) {
|
||||
ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY timer increment using low latency interface\n");
|
||||
spin_unlock_irq(¶ms->atqbal_wq.lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
spin_unlock_irq(¶ms->atqbal_wq.lock);
|
||||
|
||||
return 0;
|
||||
if (err)
|
||||
ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY timer increment using low latency interface\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4927,8 +4925,12 @@ static int ice_ptp_prep_phy_incval_e810(struct ice_hw *hw, u64 incval)
|
||||
u8 tmr_idx;
|
||||
int err;
|
||||
|
||||
if (hw->dev_caps.ts_dev_info.ll_phy_tmr_update)
|
||||
return ice_ptp_prep_phy_incval_ll_e810(hw, incval);
|
||||
if (hw->dev_caps.ts_dev_info.ll_phy_tmr_update) {
|
||||
err = ice_ptp_prep_phy_incval_ll_e810(hw, incval);
|
||||
if (err != -ETIMEDOUT)
|
||||
return err;
|
||||
ice_debug(hw, ICE_DBG_PTP, "LL incval timed out, falling back to SBQ\n");
|
||||
}
|
||||
|
||||
tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
|
||||
low = lower_32_bits(incval);
|
||||
|
||||
@@ -2408,7 +2408,7 @@ void idpf_tx_splitq_build_flow_desc(union idpf_tx_flex_desc *desc,
|
||||
struct idpf_tx_splitq_params *params,
|
||||
u16 td_cmd, u16 size)
|
||||
{
|
||||
*(u32 *)&desc->flow.qw1.cmd_dtype = (u8)(params->dtype | td_cmd);
|
||||
*(__le32 *)&desc->flow.qw1.cmd_dtype = cpu_to_le32((u8)(params->dtype | td_cmd));
|
||||
desc->flow.qw1.rxr_bufsize = cpu_to_le16((u16)size);
|
||||
desc->flow.qw1.compl_tag = cpu_to_le16(params->compl_tag);
|
||||
}
|
||||
|
||||
@@ -856,7 +856,7 @@ int rvu_mbox_handler_mcs_ctrl_pkt_rule_write(struct rvu *rvu,
|
||||
static void rvu_mcs_set_lmac_bmap(struct rvu *rvu)
|
||||
{
|
||||
struct mcs *mcs = mcs_get_pdata(0);
|
||||
unsigned long lmac_bmap;
|
||||
unsigned long lmac_bmap = 0;
|
||||
int cgx, lmac, port;
|
||||
|
||||
for (port = 0; port < mcs->hw->lmac_cnt; port++) {
|
||||
|
||||
@@ -2257,6 +2257,11 @@ static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cq
|
||||
|
||||
data_offset = wqe_offset & (page_size - 1);
|
||||
page_idx = wqe_offset >> rq->mpwqe.page_shift;
|
||||
if (unlikely(cqe_bcnt <= ETH_ZLEN + 2 * VLAN_HLEN)) {
|
||||
match = false;
|
||||
flush = true;
|
||||
}
|
||||
|
||||
if (*skb &&
|
||||
!(match && mlx5e_hw_gro_skb_has_enough_space(*skb, data_bcnt,
|
||||
page_size))) {
|
||||
|
||||
@@ -269,6 +269,8 @@ bool ionic_notifyq_service(struct ionic_cq *cq)
|
||||
if ((s64)(eid - lif->last_eid) <= 0)
|
||||
return false;
|
||||
|
||||
dma_rmb();
|
||||
|
||||
lif->last_eid = eid;
|
||||
|
||||
dev_dbg(lif->ionic->dev, "notifyq event:\n");
|
||||
@@ -314,6 +316,8 @@ bool ionic_adminq_service(struct ionic_cq *cq)
|
||||
if (!color_match(comp->color, cq->done_color))
|
||||
return false;
|
||||
|
||||
dma_rmb();
|
||||
|
||||
/* check for empty queue */
|
||||
if (q->tail_idx == q->head_idx)
|
||||
return false;
|
||||
|
||||
@@ -706,11 +706,7 @@ static void ionic_rx_clean(struct ionic_queue *q,
|
||||
__le64 *cq_desc_hwstamp;
|
||||
u64 hwstamp;
|
||||
|
||||
cq_desc_hwstamp =
|
||||
(void *)comp +
|
||||
qcq->cq.desc_size -
|
||||
sizeof(struct ionic_rxq_comp) -
|
||||
IONIC_HWSTAMP_CQ_NEGOFFSET;
|
||||
cq_desc_hwstamp = (void *)comp - IONIC_HWSTAMP_CQ_NEGOFFSET;
|
||||
|
||||
hwstamp = le64_to_cpu(*cq_desc_hwstamp);
|
||||
|
||||
@@ -734,11 +730,18 @@ static bool __ionic_rx_service(struct ionic_cq *cq, struct bpf_prog *xdp_prog)
|
||||
struct ionic_queue *q = cq->bound_q;
|
||||
struct ionic_rxq_comp *comp;
|
||||
|
||||
comp = &((struct ionic_rxq_comp *)cq->base)[cq->tail_idx];
|
||||
if (likely(cq->desc_size == sizeof(*comp)))
|
||||
comp = &((struct ionic_rxq_comp *)cq->base)[cq->tail_idx];
|
||||
else
|
||||
comp = cq->base +
|
||||
cq->desc_size * cq->tail_idx +
|
||||
cq->desc_size - sizeof(*comp);
|
||||
|
||||
if (!color_match(comp->pkt_type_color, cq->done_color))
|
||||
return false;
|
||||
|
||||
dma_rmb();
|
||||
|
||||
/* check for empty queue */
|
||||
if (q->tail_idx == q->head_idx)
|
||||
return false;
|
||||
@@ -1185,7 +1188,6 @@ static void ionic_tx_clean(struct ionic_queue *q,
|
||||
bool in_napi)
|
||||
{
|
||||
struct ionic_tx_stats *stats = q_to_tx_stats(q);
|
||||
struct ionic_qcq *qcq = q_to_qcq(q);
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (desc_info->xdpf) {
|
||||
@@ -1210,11 +1212,7 @@ static void ionic_tx_clean(struct ionic_queue *q,
|
||||
__le64 *cq_desc_hwstamp;
|
||||
u64 hwstamp;
|
||||
|
||||
cq_desc_hwstamp =
|
||||
(void *)comp +
|
||||
qcq->cq.desc_size -
|
||||
sizeof(struct ionic_txq_comp) -
|
||||
IONIC_HWSTAMP_CQ_NEGOFFSET;
|
||||
cq_desc_hwstamp = (void *)comp - IONIC_HWSTAMP_CQ_NEGOFFSET;
|
||||
|
||||
hwstamp = le64_to_cpu(*cq_desc_hwstamp);
|
||||
|
||||
@@ -1249,11 +1247,18 @@ static bool ionic_tx_service(struct ionic_cq *cq,
|
||||
unsigned int pkts = 0;
|
||||
u16 index;
|
||||
|
||||
comp = &((struct ionic_txq_comp *)cq->base)[cq->tail_idx];
|
||||
if (likely(cq->desc_size == sizeof(*comp)))
|
||||
comp = &((struct ionic_txq_comp *)cq->base)[cq->tail_idx];
|
||||
else
|
||||
comp = cq->base +
|
||||
cq->desc_size * cq->tail_idx +
|
||||
cq->desc_size - sizeof(*comp);
|
||||
|
||||
if (!color_match(comp->color, cq->done_color))
|
||||
return false;
|
||||
|
||||
dma_rmb();
|
||||
|
||||
/* clean the related q entries, there could be
|
||||
* several q entries completed for each cq completion
|
||||
*/
|
||||
|
||||
@@ -2066,7 +2066,7 @@ static int __maybe_unused cp_suspend(struct device *device)
|
||||
|
||||
/* Disable Rx and Tx */
|
||||
cpw16 (IntrMask, 0);
|
||||
cpw8 (Cmd, cpr8 (Cmd) & (~RxOn | ~TxOn));
|
||||
cpw8 (Cmd, cpr8 (Cmd) & ~(RxOn | TxOn));
|
||||
|
||||
spin_unlock_irqrestore (&cp->lock, flags);
|
||||
|
||||
|
||||
@@ -1028,6 +1028,7 @@ struct ravb_ptp_perout {
|
||||
struct ravb_ptp {
|
||||
struct ptp_clock *clock;
|
||||
struct ptp_clock_info info;
|
||||
int phc_index;
|
||||
u32 default_addend;
|
||||
u32 current_addend;
|
||||
int extts[N_EXT_TS];
|
||||
@@ -1123,6 +1124,8 @@ struct ravb_private {
|
||||
int msg_enable;
|
||||
int speed;
|
||||
int emac_irq;
|
||||
int err_irq;
|
||||
int mgmt_irq;
|
||||
|
||||
unsigned no_avb_link:1;
|
||||
unsigned avb_link_active_low:1;
|
||||
|
||||
@@ -1779,7 +1779,7 @@ static int ravb_get_ts_info(struct net_device *ndev,
|
||||
(1 << HWTSTAMP_FILTER_NONE) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
|
||||
(1 << HWTSTAMP_FILTER_ALL);
|
||||
info->phc_index = ptp_clock_index(priv->ptp.clock);
|
||||
info->phc_index = READ_ONCE(priv->ptp.phc_index);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -2885,11 +2885,13 @@ static int ravb_setup_irqs(struct ravb_private *priv)
|
||||
return error;
|
||||
|
||||
if (info->err_mgmt_irqs) {
|
||||
error = ravb_setup_irq(priv, "err_a", "err_a", NULL, ravb_multi_interrupt);
|
||||
error = ravb_setup_irq(priv, "err_a", "err_a", &priv->err_irq,
|
||||
ravb_multi_interrupt);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = ravb_setup_irq(priv, "mgmt_a", "mgmt_a", NULL, ravb_multi_interrupt);
|
||||
error = ravb_setup_irq(priv, "mgmt_a", "mgmt_a", &priv->mgmt_irq,
|
||||
ravb_multi_interrupt);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
@@ -2953,6 +2955,7 @@ static int ravb_probe(struct platform_device *pdev)
|
||||
priv->rstc = rstc;
|
||||
priv->ndev = ndev;
|
||||
priv->pdev = pdev;
|
||||
priv->ptp.phc_index = -1;
|
||||
priv->num_tx_ring[RAVB_BE] = BE_TX_RING_SIZE;
|
||||
priv->num_rx_ring[RAVB_BE] = BE_RX_RING_SIZE;
|
||||
if (info->nc_queues) {
|
||||
|
||||
@@ -289,16 +289,17 @@ static const struct ptp_clock_info ravb_ptp_info = {
|
||||
void ravb_ptp_interrupt(struct net_device *ndev)
|
||||
{
|
||||
struct ravb_private *priv = netdev_priv(ndev);
|
||||
struct ptp_clock *clock = READ_ONCE(priv->ptp.clock);
|
||||
u32 gis = ravb_read(ndev, GIS);
|
||||
|
||||
gis &= ravb_read(ndev, GIC);
|
||||
if (gis & GIS_PTCF) {
|
||||
if ((gis & GIS_PTCF) && clock) {
|
||||
struct ptp_clock_event event;
|
||||
|
||||
event.type = PTP_CLOCK_EXTTS;
|
||||
event.index = 0;
|
||||
event.timestamp = ravb_read(ndev, GCPT);
|
||||
ptp_clock_event(priv->ptp.clock, &event);
|
||||
ptp_clock_event(clock, &event);
|
||||
}
|
||||
if (gis & GIS_PTMF) {
|
||||
struct ravb_ptp_perout *perout = priv->ptp.perout;
|
||||
@@ -315,6 +316,7 @@ void ravb_ptp_interrupt(struct net_device *ndev)
|
||||
void ravb_ptp_init(struct net_device *ndev, struct platform_device *pdev)
|
||||
{
|
||||
struct ravb_private *priv = netdev_priv(ndev);
|
||||
struct ptp_clock *clock;
|
||||
unsigned long flags;
|
||||
|
||||
priv->ptp.info = ravb_ptp_info;
|
||||
@@ -327,15 +329,45 @@ void ravb_ptp_init(struct net_device *ndev, struct platform_device *pdev)
|
||||
ravb_modify(ndev, GCCR, GCCR_TCSS, GCCR_TCSS_ADJGPTP);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
priv->ptp.clock = ptp_clock_register(&priv->ptp.info, &pdev->dev);
|
||||
clock = ptp_clock_register(&priv->ptp.info, &pdev->dev);
|
||||
if (IS_ERR(clock)) {
|
||||
netdev_err(ndev, "failed to register PTP clock: %pe\n", clock);
|
||||
clock = NULL;
|
||||
}
|
||||
|
||||
WRITE_ONCE(priv->ptp.clock, clock);
|
||||
if (clock)
|
||||
WRITE_ONCE(priv->ptp.phc_index, ptp_clock_index(clock));
|
||||
}
|
||||
|
||||
static void ravb_ptp_disable(struct net_device *ndev)
|
||||
{
|
||||
ravb_write(ndev, 0, GIC);
|
||||
ravb_write(ndev, 0, GIS);
|
||||
}
|
||||
|
||||
static void ravb_ptp_sync_irqs(struct net_device *ndev)
|
||||
{
|
||||
struct ravb_private *priv = netdev_priv(ndev);
|
||||
|
||||
synchronize_irq(ndev->irq);
|
||||
if (priv->info->err_mgmt_irqs) {
|
||||
synchronize_irq(priv->err_irq);
|
||||
synchronize_irq(priv->mgmt_irq);
|
||||
}
|
||||
}
|
||||
|
||||
void ravb_ptp_stop(struct net_device *ndev)
|
||||
{
|
||||
struct ravb_private *priv = netdev_priv(ndev);
|
||||
struct ptp_clock *clock;
|
||||
|
||||
ravb_write(ndev, 0, GIC);
|
||||
ravb_write(ndev, 0, GIS);
|
||||
WRITE_ONCE(priv->ptp.phc_index, -1);
|
||||
clock = xchg(&priv->ptp.clock, NULL);
|
||||
|
||||
ptp_clock_unregister(priv->ptp.clock);
|
||||
ravb_ptp_disable(ndev);
|
||||
ravb_ptp_sync_irqs(ndev);
|
||||
|
||||
if (clock)
|
||||
ptp_clock_unregister(clock);
|
||||
}
|
||||
|
||||
@@ -74,7 +74,9 @@ int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
|
||||
|
||||
switch (cmd) {
|
||||
case PPPIOCGCHAN: {
|
||||
struct sk_buff *skb;
|
||||
int index;
|
||||
|
||||
rc = -ENOTCONN;
|
||||
if (!(sk->sk_state & PPPOX_CONNECTED))
|
||||
break;
|
||||
@@ -85,7 +87,22 @@ int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
|
||||
break;
|
||||
|
||||
rc = 0;
|
||||
/* PPPIOCGCHAN historically marks the userspace handoff to
|
||||
* generic PPP; pppd then attaches the returned channel to
|
||||
* /dev/ppp.
|
||||
*/
|
||||
sk->sk_state |= PPPOX_BOUND;
|
||||
/* Let lockless receive paths finish queueing against the old
|
||||
* state.
|
||||
*/
|
||||
synchronize_net();
|
||||
/* Drain packets queued before the handoff because a bound
|
||||
* socket is no longer readable.
|
||||
*/
|
||||
while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
|
||||
skb_orphan(skb);
|
||||
ppp_input(&po->chan, skb);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -626,6 +626,14 @@ static int tbnet_alloc_tx_buffers(struct tbnet *net)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tbnet_connect_failed(struct tbnet *net)
|
||||
{
|
||||
/* Leave login_received set: only the peer can make it true again. */
|
||||
mutex_lock(&net->connection_lock);
|
||||
net->login_sent = false;
|
||||
mutex_unlock(&net->connection_lock);
|
||||
}
|
||||
|
||||
static void tbnet_connected_work(struct work_struct *work)
|
||||
{
|
||||
struct tbnet *net = container_of(work, typeof(*net), connected_work);
|
||||
@@ -647,6 +655,9 @@ static void tbnet_connected_work(struct work_struct *work)
|
||||
ret = tb_xdomain_alloc_in_hopid(net->xd, net->remote_transmit_path);
|
||||
if (ret != net->remote_transmit_path) {
|
||||
netdev_err(net->dev, "failed to allocate Rx HopID\n");
|
||||
if (ret >= 0)
|
||||
tb_xdomain_release_in_hopid(net->xd, ret);
|
||||
tbnet_connect_failed(net);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -691,6 +702,7 @@ static void tbnet_connected_work(struct work_struct *work)
|
||||
tb_ring_stop(net->rx_ring.ring);
|
||||
tb_ring_stop(net->tx_ring.ring);
|
||||
tb_xdomain_release_in_hopid(net->xd, net->remote_transmit_path);
|
||||
tbnet_connect_failed(net);
|
||||
}
|
||||
|
||||
static void tbnet_login_work(struct work_struct *work)
|
||||
|
||||
@@ -1186,11 +1186,16 @@ static netdev_features_t tun_net_fix_features(struct net_device *dev,
|
||||
static void tun_set_headroom(struct net_device *dev, int new_hr)
|
||||
{
|
||||
struct tun_struct *tun = netdev_priv(dev);
|
||||
size_t max_headroom;
|
||||
|
||||
if (new_hr < NET_SKB_PAD)
|
||||
new_hr = NET_SKB_PAD;
|
||||
max_headroom = min_t(size_t, SKB_MAX_HEAD(0), U16_MAX - 1);
|
||||
|
||||
tun->align = new_hr;
|
||||
if ((tun->flags & TUN_TYPE_MASK) == IFF_TAP)
|
||||
max_headroom -= ETH_HLEN + NET_IP_ALIGN;
|
||||
else
|
||||
max_headroom -= 1;
|
||||
|
||||
tun->align = clamp_t(int, new_hr, NET_SKB_PAD, max_headroom);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1901,7 +1906,13 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
|
||||
switch (tun->flags & TUN_TYPE_MASK) {
|
||||
case IFF_TUN:
|
||||
if (tun->flags & IFF_NO_PI) {
|
||||
u8 ip_version = skb->len ? (skb->data[0] >> 4) : 0;
|
||||
u8 ip_version;
|
||||
|
||||
if (!pskb_may_pull(skb, 1)) {
|
||||
err = -EINVAL;
|
||||
goto drop;
|
||||
}
|
||||
ip_version = skb->data[0] >> 4;
|
||||
|
||||
switch (ip_version) {
|
||||
case 4:
|
||||
@@ -1921,7 +1932,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
|
||||
skb->dev = tun->dev;
|
||||
break;
|
||||
case IFF_TAP:
|
||||
if (frags && !pskb_may_pull(skb, ETH_HLEN)) {
|
||||
if (!pskb_may_pull(skb, ETH_HLEN)) {
|
||||
err = -ENOMEM;
|
||||
drop_reason = SKB_DROP_REASON_HDR_TRUNC;
|
||||
goto drop;
|
||||
|
||||
@@ -3444,17 +3444,31 @@ static void virtnet_rx_resume_all(struct virtnet_info *vi)
|
||||
static int virtnet_rx_resize(struct virtnet_info *vi,
|
||||
struct receive_queue *rq, u32 ring_num)
|
||||
{
|
||||
unsigned int old_ring_num = virtqueue_get_vring_size(rq->vq);
|
||||
struct xdp_buff **tmp_xsk_buffs = NULL;
|
||||
int err, qindex;
|
||||
|
||||
qindex = rq - vi->rq;
|
||||
|
||||
if (rq->xsk_pool && ring_num > old_ring_num) {
|
||||
tmp_xsk_buffs = kvzalloc_objs(*tmp_xsk_buffs, ring_num);
|
||||
if (!tmp_xsk_buffs)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
virtnet_rx_pause(vi, rq);
|
||||
|
||||
err = virtqueue_resize(rq->vq, ring_num, virtnet_rq_unmap_free_buf, NULL);
|
||||
|
||||
/* virtqueue_resize may have changed the size even if err != 0 */
|
||||
if (tmp_xsk_buffs && virtqueue_get_vring_size(rq->vq) > old_ring_num)
|
||||
swap(rq->xsk_buffs, tmp_xsk_buffs);
|
||||
|
||||
if (err)
|
||||
netdev_err(vi->dev, "resize rx fail: rx queue index: %d err: %d\n", qindex, err);
|
||||
|
||||
virtnet_rx_resume(vi, rq, true);
|
||||
kvfree(tmp_xsk_buffs);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@@ -3058,18 +3058,19 @@ vxlan_fdb_flush_match_remotes(struct vxlan_fdb *f, struct vxlan_dev *vxlan,
|
||||
const struct vxlan_fdb_flush_desc *desc,
|
||||
bool *p_destroy_fdb)
|
||||
{
|
||||
bool remotes_flushed = false;
|
||||
struct vxlan_rdst *rd, *tmp;
|
||||
|
||||
list_for_each_entry_safe(rd, tmp, &f->remotes, list) {
|
||||
if (!vxlan_fdb_flush_remote_matches(desc, rd))
|
||||
continue;
|
||||
|
||||
vxlan_fdb_dst_destroy(vxlan, f, rd, true);
|
||||
remotes_flushed = true;
|
||||
}
|
||||
if (list_is_singular(&f->remotes)) {
|
||||
*p_destroy_fdb = true;
|
||||
return;
|
||||
}
|
||||
|
||||
*p_destroy_fdb = remotes_flushed && list_empty(&f->remotes);
|
||||
vxlan_fdb_dst_destroy(vxlan, f, rd, true);
|
||||
}
|
||||
}
|
||||
|
||||
/* Purge the forwarding table */
|
||||
|
||||
@@ -1428,14 +1428,17 @@ static void vxlan_mdb_flush(struct vxlan_dev *vxlan,
|
||||
struct vxlan_mdb_entry *mdb_entry;
|
||||
struct hlist_node *tmp;
|
||||
|
||||
/* The removal of an entry cannot trigger the removal of another entry
|
||||
* since entries are always added to the head of the list.
|
||||
*/
|
||||
hlist_for_each_entry_safe(mdb_entry, tmp, &vxlan->mdb_list, mdb_node) {
|
||||
if (desc->src_vni && desc->src_vni != mdb_entry->key.vni)
|
||||
continue;
|
||||
|
||||
vxlan_mdb_remotes_flush(vxlan, mdb_entry, desc);
|
||||
/* The flush can remove the (S, G) entries created for the
|
||||
* source list of this entry, including the one saved by
|
||||
* hlist_for_each_entry_safe(), so re-read it while this entry
|
||||
* is still linked.
|
||||
*/
|
||||
tmp = mdb_entry->mdb_node.next;
|
||||
/* Entry will only be removed if its remotes list is empty. */
|
||||
vxlan_mdb_entry_put(vxlan, mdb_entry);
|
||||
}
|
||||
|
||||
@@ -462,10 +462,8 @@ static int vxlan_vnifilter_dump(struct sk_buff *skb, struct netlink_callback *cb
|
||||
static const struct nla_policy vni_filter_entry_policy[VXLAN_VNIFILTER_ENTRY_MAX + 1] = {
|
||||
[VXLAN_VNIFILTER_ENTRY_START] = { .type = NLA_U32 },
|
||||
[VXLAN_VNIFILTER_ENTRY_END] = { .type = NLA_U32 },
|
||||
[VXLAN_VNIFILTER_ENTRY_GROUP] = { .type = NLA_BINARY,
|
||||
.len = sizeof_field(struct iphdr, daddr) },
|
||||
[VXLAN_VNIFILTER_ENTRY_GROUP6] = { .type = NLA_BINARY,
|
||||
.len = sizeof(struct in6_addr) },
|
||||
[VXLAN_VNIFILTER_ENTRY_GROUP] = NLA_POLICY_EXACT_LEN(sizeof_field(struct iphdr, daddr)),
|
||||
[VXLAN_VNIFILTER_ENTRY_GROUP6] = NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)),
|
||||
};
|
||||
|
||||
static const struct nla_policy vni_filter_policy[VXLAN_VNIFILTER_MAX + 1] = {
|
||||
|
||||
@@ -166,9 +166,36 @@ static int fdp_nci_i2c_read(struct fdp_i2c_phy *phy, struct sk_buff **skb)
|
||||
/* Packet that contains a length */
|
||||
if (tmp[0] == 0 && tmp[1] == 0) {
|
||||
phy->next_read_size = (tmp[2] << 8) + tmp[3] + 3;
|
||||
|
||||
/*
|
||||
* next_read_size is taken from the device and is used
|
||||
* as the i2c_master_recv() count for the next packet
|
||||
* and as the data skb size. A value above the receive
|
||||
* buffer overflows tmp[]; one below the minimum frame
|
||||
* size runs the header/LRC strip and the length-field
|
||||
* read past a short receive. Either way the packet is
|
||||
* corrupt: drop it and force resynchronization.
|
||||
*/
|
||||
if (phy->next_read_size < FDP_NCI_I2C_MIN_PAYLOAD ||
|
||||
phy->next_read_size > FDP_NCI_I2C_MAX_PAYLOAD) {
|
||||
dev_dbg(&client->dev, "%s: corrupted packet\n",
|
||||
__func__);
|
||||
phy->next_read_size = FDP_NCI_I2C_MIN_PAYLOAD;
|
||||
goto flush;
|
||||
}
|
||||
} else {
|
||||
phy->next_read_size = FDP_NCI_I2C_MIN_PAYLOAD;
|
||||
|
||||
/*
|
||||
* Only one data packet is delivered per call; if the
|
||||
* device sends another, do not overwrite and leak the
|
||||
* skb allocated for the previous one.
|
||||
*/
|
||||
if (*skb) {
|
||||
kfree_skb(*skb);
|
||||
*skb = NULL;
|
||||
}
|
||||
|
||||
*skb = alloc_skb(len, GFP_KERNEL);
|
||||
if (*skb == NULL) {
|
||||
r = -ENOMEM;
|
||||
|
||||
@@ -483,13 +483,19 @@ static void microread_target_discovered(struct nfc_hci_dev *hdev, u8 gate,
|
||||
|
||||
switch (gate) {
|
||||
case MICROREAD_GATE_ID_MREAD_ISO_A:
|
||||
if (skb->len <= MICROREAD_EMCF_A_LEN) {
|
||||
r = -EINVAL;
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
targets->supported_protocols =
|
||||
nfc_hci_sak_to_protocol(skb->data[MICROREAD_EMCF_A_SAK]);
|
||||
targets->sens_res =
|
||||
be16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_A_ATQA]);
|
||||
targets->sel_res = skb->data[MICROREAD_EMCF_A_SAK];
|
||||
targets->nfcid1_len = skb->data[MICROREAD_EMCF_A_LEN];
|
||||
if (targets->nfcid1_len > sizeof(targets->nfcid1)) {
|
||||
if (targets->nfcid1_len > sizeof(targets->nfcid1) ||
|
||||
targets->nfcid1_len > skb->len - MICROREAD_EMCF_A_UID) {
|
||||
r = -EINVAL;
|
||||
goto exit_free;
|
||||
}
|
||||
@@ -497,13 +503,19 @@ static void microread_target_discovered(struct nfc_hci_dev *hdev, u8 gate,
|
||||
targets->nfcid1_len);
|
||||
break;
|
||||
case MICROREAD_GATE_ID_MREAD_ISO_A_3:
|
||||
if (skb->len <= MICROREAD_EMCF_A3_LEN) {
|
||||
r = -EINVAL;
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
targets->supported_protocols =
|
||||
nfc_hci_sak_to_protocol(skb->data[MICROREAD_EMCF_A3_SAK]);
|
||||
targets->sens_res =
|
||||
be16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_A3_ATQA]);
|
||||
targets->sel_res = skb->data[MICROREAD_EMCF_A3_SAK];
|
||||
targets->nfcid1_len = skb->data[MICROREAD_EMCF_A3_LEN];
|
||||
if (targets->nfcid1_len > sizeof(targets->nfcid1)) {
|
||||
if (targets->nfcid1_len > sizeof(targets->nfcid1) ||
|
||||
targets->nfcid1_len > skb->len - MICROREAD_EMCF_A3_UID) {
|
||||
r = -EINVAL;
|
||||
goto exit_free;
|
||||
}
|
||||
@@ -511,11 +523,21 @@ static void microread_target_discovered(struct nfc_hci_dev *hdev, u8 gate,
|
||||
targets->nfcid1_len);
|
||||
break;
|
||||
case MICROREAD_GATE_ID_MREAD_ISO_B:
|
||||
if (skb->len < MICROREAD_EMCF_B_UID + 4) {
|
||||
r = -EINVAL;
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
targets->supported_protocols = NFC_PROTO_ISO14443_B_MASK;
|
||||
memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_B_UID], 4);
|
||||
targets->nfcid1_len = 4;
|
||||
break;
|
||||
case MICROREAD_GATE_ID_MREAD_NFC_T1:
|
||||
if (skb->len < MICROREAD_EMCF_T1_UID + 4) {
|
||||
r = -EINVAL;
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
targets->supported_protocols = NFC_PROTO_JEWEL_MASK;
|
||||
targets->sens_res =
|
||||
le16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_T1_ATQA]);
|
||||
@@ -523,6 +545,11 @@ static void microread_target_discovered(struct nfc_hci_dev *hdev, u8 gate,
|
||||
targets->nfcid1_len = 4;
|
||||
break;
|
||||
case MICROREAD_GATE_ID_MREAD_NFC_T3:
|
||||
if (skb->len < MICROREAD_EMCF_T3_UID + 8) {
|
||||
r = -EINVAL;
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
targets->supported_protocols = NFC_PROTO_FELICA_MASK;
|
||||
memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_T3_UID], 8);
|
||||
targets->nfcid1_len = 8;
|
||||
|
||||
@@ -434,6 +434,18 @@ static int pn533_send_async_complete(struct pn533 *dev)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pn533_send_cmd_frame(struct pn533 *dev, struct pn533_cmd *cmd)
|
||||
{
|
||||
struct sk_buff *req = cmd->req;
|
||||
int rc;
|
||||
|
||||
skb_get(req);
|
||||
dev->cmd = cmd;
|
||||
rc = dev->phy_ops->send_frame(dev, req);
|
||||
dev_kfree_skb(req);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __pn533_send_async(struct pn533 *dev, u8 cmd_code,
|
||||
struct sk_buff *req,
|
||||
pn533_send_async_complete_t complete_cb,
|
||||
@@ -458,8 +470,7 @@ static int __pn533_send_async(struct pn533 *dev, u8 cmd_code,
|
||||
mutex_lock(&dev->cmd_lock);
|
||||
|
||||
if (!dev->cmd_pending) {
|
||||
dev->cmd = cmd;
|
||||
rc = dev->phy_ops->send_frame(dev, req);
|
||||
rc = pn533_send_cmd_frame(dev, cmd);
|
||||
if (rc) {
|
||||
dev->cmd = NULL;
|
||||
goto error;
|
||||
@@ -529,8 +540,7 @@ static int pn533_send_cmd_direct_async(struct pn533 *dev, u8 cmd_code,
|
||||
|
||||
pn533_build_cmd_frame(dev, cmd_code, req);
|
||||
|
||||
dev->cmd = cmd;
|
||||
rc = dev->phy_ops->send_frame(dev, req);
|
||||
rc = pn533_send_cmd_frame(dev, cmd);
|
||||
if (rc < 0) {
|
||||
dev->cmd = NULL;
|
||||
kfree(cmd);
|
||||
@@ -569,8 +579,7 @@ static void pn533_wq_cmd(struct work_struct *work)
|
||||
|
||||
mutex_unlock(&dev->cmd_lock);
|
||||
|
||||
dev->cmd = cmd;
|
||||
rc = dev->phy_ops->send_frame(dev, cmd->req);
|
||||
rc = pn533_send_cmd_frame(dev, cmd);
|
||||
if (rc < 0) {
|
||||
dev->cmd = NULL;
|
||||
dev_kfree_skb(cmd->req);
|
||||
@@ -2801,6 +2810,7 @@ void pn53x_common_clean(struct pn533 *priv)
|
||||
destroy_workqueue(priv->wq);
|
||||
|
||||
skb_queue_purge(&priv->resp_q);
|
||||
skb_queue_purge(&priv->fragment_skb);
|
||||
|
||||
list_for_each_entry_safe(cmd, n, &priv->cmd_queue, queue) {
|
||||
list_del(&cmd->queue);
|
||||
|
||||
@@ -205,6 +205,9 @@ static int st21nfca_tm_recv_atr_req(struct nfc_hci_dev *hdev,
|
||||
if (atr_req->length < sizeof(struct st21nfca_atr_req))
|
||||
return -EPROTO;
|
||||
|
||||
if (atr_req->length > skb->len)
|
||||
return -EPROTO;
|
||||
|
||||
r = st21nfca_tm_send_atr_res(hdev, atr_req);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
@@ -482,6 +482,9 @@ static int net_timer_enable_perout(struct netc_timer *priv,
|
||||
|
||||
netc_timer_enable_periodic_pulse(priv, channel);
|
||||
} else {
|
||||
if (!pp->enabled)
|
||||
goto unlock_spinlock;
|
||||
|
||||
netc_timer_disable_periodic_pulse(priv, channel);
|
||||
priv->fs_alarm_bitmap &= ~BIT(pp->alarm_id);
|
||||
memset(pp, 0, sizeof(*pp));
|
||||
|
||||
@@ -372,6 +372,12 @@ static int vmclock_miscdev_mmap(struct file *fp, struct vm_area_struct *vma)
|
||||
if ((vma->vm_flags & (VM_READ|VM_WRITE)) != VM_READ)
|
||||
return -EROFS;
|
||||
|
||||
/*
|
||||
* Restrict the read-only mapping so it cannot be upgraded to
|
||||
* writable later with mprotect().
|
||||
*/
|
||||
vm_flags_clear(vma, VM_MAYWRITE);
|
||||
|
||||
if (vma->vm_end - vma->vm_start != PAGE_SIZE || vma->vm_pgoff)
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
@@ -52,13 +52,10 @@ struct vsock_sock {
|
||||
* The listening socket is the head for both lists. Sockets created
|
||||
* for connection requests are placed in the pending list until they
|
||||
* are connected, at which point they are put in the accept queue list
|
||||
* so they can be accepted in accept(). If accept() cannot accept the
|
||||
* connection, it is marked as rejected so the cleanup function knows
|
||||
* to clean up the socket.
|
||||
* so they can be accepted in accept().
|
||||
*/
|
||||
struct list_head pending_links;
|
||||
struct list_head accept_queue;
|
||||
bool rejected;
|
||||
struct delayed_work connect_work;
|
||||
struct delayed_work pending_work;
|
||||
struct delayed_work close_work;
|
||||
|
||||
@@ -628,8 +628,7 @@ struct metadata_dst *iptunnel_metadata_reply(struct metadata_dst *md,
|
||||
int skb_tunnel_check_pmtu(struct sk_buff *skb, struct dst_entry *encap_dst,
|
||||
int headroom, bool reply);
|
||||
|
||||
static inline void ip_tunnel_adj_headroom(struct net_device *dev,
|
||||
unsigned int headroom)
|
||||
static inline unsigned int ip_tunnel_limit_headroom(unsigned int headroom)
|
||||
{
|
||||
/* we must cap headroom to some upperlimit, else pskb_expand_head
|
||||
* will overflow header offsets in skb_headers_offset_update().
|
||||
@@ -639,6 +638,14 @@ static inline void ip_tunnel_adj_headroom(struct net_device *dev,
|
||||
if (headroom > max_allowed)
|
||||
headroom = max_allowed;
|
||||
|
||||
return headroom;
|
||||
}
|
||||
|
||||
static inline void ip_tunnel_adj_headroom(struct net_device *dev,
|
||||
unsigned int headroom)
|
||||
{
|
||||
headroom = ip_tunnel_limit_headroom(headroom);
|
||||
|
||||
if (headroom > READ_ONCE(dev->needed_headroom))
|
||||
WRITE_ONCE(dev->needed_headroom, headroom);
|
||||
}
|
||||
|
||||
@@ -1136,7 +1136,7 @@ int __br_vlan_set_default_pvid(struct net_bridge *br, u16 pvid,
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (br_vlan_delete(br, old_pvid))
|
||||
if (!br_vlan_delete(br, old_pvid))
|
||||
br_vlan_notify(br, NULL, old_pvid, 0, RTM_DELVLAN);
|
||||
br_vlan_notify(br, NULL, pvid, 0, RTM_NEWVLAN);
|
||||
__set_bit(0, changed);
|
||||
@@ -1158,7 +1158,7 @@ int __br_vlan_set_default_pvid(struct net_bridge *br, u16 pvid,
|
||||
&vlchange, extack);
|
||||
if (err)
|
||||
goto err_port;
|
||||
if (nbp_vlan_delete(p, old_pvid))
|
||||
if (!nbp_vlan_delete(p, old_pvid))
|
||||
br_vlan_notify(br, p, old_pvid, 0, RTM_DELVLAN);
|
||||
br_vlan_notify(p->br, p, pvid, 0, RTM_NEWVLAN);
|
||||
__set_bit(p->port_no, changed);
|
||||
|
||||
@@ -10383,6 +10383,37 @@ static int dev_xdp_install(struct net_device *dev, enum bpf_xdp_mode mode,
|
||||
|
||||
netdev_assert_locked_ops_compat(dev);
|
||||
|
||||
if (prog) {
|
||||
enum bpf_xdp_mode other_mode = mode == XDP_MODE_SKB
|
||||
? XDP_MODE_DRV : XDP_MODE_SKB;
|
||||
bool offload = mode == XDP_MODE_HW;
|
||||
|
||||
if (!offload && dev_xdp_prog(dev, other_mode)) {
|
||||
NL_SET_ERR_MSG(extack, "Native and generic XDP can't be active at the same time");
|
||||
return -EEXIST;
|
||||
}
|
||||
if (!offload && bpf_prog_is_offloaded(prog->aux)) {
|
||||
NL_SET_ERR_MSG(extack, "Using offloaded program without HW_MODE flag is not supported");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (bpf_prog_is_dev_bound(prog->aux) && !bpf_offload_dev_match(prog, dev)) {
|
||||
NL_SET_ERR_MSG(extack, "Program bound to different device");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (bpf_prog_is_dev_bound(prog->aux) && mode == XDP_MODE_SKB) {
|
||||
NL_SET_ERR_MSG(extack, "Can't attach device-bound programs in generic mode");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (prog->expected_attach_type == BPF_XDP_DEVMAP) {
|
||||
NL_SET_ERR_MSG(extack, "BPF_XDP_DEVMAP programs can not be attached to a device");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (prog->expected_attach_type == BPF_XDP_CPUMAP) {
|
||||
NL_SET_ERR_MSG(extack, "BPF_XDP_CPUMAP programs can not be attached to a device");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (dev->cfg->hds_config == ETHTOOL_TCP_DATA_SPLIT_ENABLED &&
|
||||
prog && !prog->aux->xdp_has_frags) {
|
||||
NL_SET_ERR_MSG(extack, "unable to install XDP to device using tcp-data-split");
|
||||
@@ -10522,38 +10553,10 @@ static int dev_xdp_attach(struct net_device *dev, struct netlink_ext_ack *extack
|
||||
new_prog = link->link.prog;
|
||||
|
||||
if (new_prog) {
|
||||
bool offload = mode == XDP_MODE_HW;
|
||||
enum bpf_xdp_mode other_mode = mode == XDP_MODE_SKB
|
||||
? XDP_MODE_DRV : XDP_MODE_SKB;
|
||||
|
||||
if ((flags & XDP_FLAGS_UPDATE_IF_NOEXIST) && cur_prog) {
|
||||
NL_SET_ERR_MSG(extack, "XDP program already attached");
|
||||
return -EBUSY;
|
||||
}
|
||||
if (!offload && dev_xdp_prog(dev, other_mode)) {
|
||||
NL_SET_ERR_MSG(extack, "Native and generic XDP can't be active at the same time");
|
||||
return -EEXIST;
|
||||
}
|
||||
if (!offload && bpf_prog_is_offloaded(new_prog->aux)) {
|
||||
NL_SET_ERR_MSG(extack, "Using offloaded program without HW_MODE flag is not supported");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (bpf_prog_is_dev_bound(new_prog->aux) && !bpf_offload_dev_match(new_prog, dev)) {
|
||||
NL_SET_ERR_MSG(extack, "Program bound to different device");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (bpf_prog_is_dev_bound(new_prog->aux) && mode == XDP_MODE_SKB) {
|
||||
NL_SET_ERR_MSG(extack, "Can't attach device-bound programs in generic mode");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (new_prog->expected_attach_type == BPF_XDP_DEVMAP) {
|
||||
NL_SET_ERR_MSG(extack, "BPF_XDP_DEVMAP programs can not be attached to a device");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (new_prog->expected_attach_type == BPF_XDP_CPUMAP) {
|
||||
NL_SET_ERR_MSG(extack, "BPF_XDP_CPUMAP programs can not be attached to a device");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* don't call drivers if the effective program didn't change */
|
||||
@@ -12222,6 +12225,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
|
||||
free_percpu(dev->pcpu_refcnt);
|
||||
free_dev:
|
||||
#endif
|
||||
ref_tracker_dir_exit(&dev->refcnt_tracker);
|
||||
kvfree(dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -500,29 +500,40 @@ static int page_pool_register_dma_index(struct page_pool *pool,
|
||||
return err;
|
||||
}
|
||||
|
||||
static int page_pool_release_dma_index(struct page_pool *pool,
|
||||
netmem_ref netmem)
|
||||
static void __page_pool_unmap_netmem_dma(struct page_pool *pool,
|
||||
netmem_ref netmem)
|
||||
{
|
||||
struct page *old, *page = netmem_to_page(netmem);
|
||||
unsigned long id;
|
||||
dma_addr_t dma;
|
||||
|
||||
if (unlikely(!PP_DMA_INDEX_BITS))
|
||||
return 0;
|
||||
if (!pool->dma_map)
|
||||
return;
|
||||
|
||||
id = netmem_get_dma_index(netmem);
|
||||
if (!id)
|
||||
return -1;
|
||||
/* Cache dma_addr before xa_cmpxchg. The scrub path holds no page ref;
|
||||
* the unref path calls put_page() regardless of cmpxchg outcome, so
|
||||
* after the cmpxchg we cannot safely touch netmem fields.
|
||||
*/
|
||||
dma = page_pool_get_dma_addr_netmem(netmem);
|
||||
|
||||
if (in_softirq())
|
||||
old = xa_cmpxchg(&pool->dma_mapped, id, page, NULL, 0);
|
||||
else
|
||||
old = xa_cmpxchg_bh(&pool->dma_mapped, id, page, NULL, 0);
|
||||
if (old != page)
|
||||
return -1;
|
||||
if (likely(PP_DMA_INDEX_BITS)) {
|
||||
id = netmem_get_dma_index(netmem);
|
||||
if (!id)
|
||||
return;
|
||||
|
||||
netmem_set_dma_index(netmem, 0);
|
||||
if (in_softirq())
|
||||
old = xa_cmpxchg(&pool->dma_mapped,
|
||||
id, page, NULL, 0);
|
||||
else
|
||||
old = xa_cmpxchg_bh(&pool->dma_mapped,
|
||||
id, page, NULL, 0);
|
||||
if (old != page)
|
||||
return;
|
||||
}
|
||||
|
||||
return 0;
|
||||
dma_unmap_page_attrs(pool->p.dev, dma,
|
||||
PAGE_SIZE << pool->p.order, pool->p.dma_dir,
|
||||
DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING);
|
||||
}
|
||||
|
||||
static bool page_pool_dma_map(struct page_pool *pool, netmem_ref netmem, gfp_t gfp)
|
||||
@@ -728,24 +739,16 @@ void page_pool_clear_pp_info(netmem_ref netmem)
|
||||
static __always_inline void __page_pool_release_netmem_dma(struct page_pool *pool,
|
||||
netmem_ref netmem)
|
||||
{
|
||||
dma_addr_t dma;
|
||||
|
||||
/* Caller must hold a page ref: __page_pool_unmap_netmem_dma() is
|
||||
* safe without a ref, but the field clears below require it.
|
||||
*/
|
||||
if (!pool->dma_map)
|
||||
/* Always account for inflight pages, even if we didn't
|
||||
* map them
|
||||
*/
|
||||
return;
|
||||
|
||||
if (page_pool_release_dma_index(pool, netmem))
|
||||
return;
|
||||
|
||||
dma = page_pool_get_dma_addr_netmem(netmem);
|
||||
|
||||
/* When page is unmapped, it cannot be returned to our pool */
|
||||
dma_unmap_page_attrs(pool->p.dev, dma,
|
||||
PAGE_SIZE << pool->p.order, pool->p.dma_dir,
|
||||
DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING);
|
||||
__page_pool_unmap_netmem_dma(pool, netmem);
|
||||
page_pool_set_dma_addr_netmem(netmem, 0);
|
||||
if (likely(PP_DMA_INDEX_BITS))
|
||||
netmem_set_dma_index(netmem, 0);
|
||||
}
|
||||
|
||||
/* Disconnects a page (from a page_pool). API users can have a need
|
||||
@@ -1171,8 +1174,9 @@ static void page_pool_scrub(struct page_pool *pool)
|
||||
synchronize_net();
|
||||
}
|
||||
|
||||
/* No page ref, dma-unmap only. */
|
||||
xa_for_each(&pool->dma_mapped, id, ptr)
|
||||
__page_pool_release_netmem_dma(pool, page_to_netmem((struct page *)ptr));
|
||||
__page_pool_unmap_netmem_dma(pool, page_to_netmem((struct page *)ptr));
|
||||
}
|
||||
|
||||
/* No more consumers should exist, but producers could still
|
||||
|
||||
@@ -854,6 +854,8 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
|
||||
hsr_del_ports(hsr);
|
||||
err_add_master:
|
||||
hsr_del_self_node(hsr);
|
||||
hsr_del_nodes(&hsr->node_db);
|
||||
hsr_del_nodes(&hsr->proxy_node_db);
|
||||
|
||||
if (unregister)
|
||||
unregister_netdevice(hsr_dev);
|
||||
|
||||
@@ -790,6 +790,10 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
|
||||
*/
|
||||
|
||||
hlen = iph->ihl * 4;
|
||||
if (mtu < hlen + 8) {
|
||||
err = -EMSGSIZE;
|
||||
goto fail;
|
||||
}
|
||||
mtu = mtu - hlen; /* Size of data space */
|
||||
IPCB(skb)->flags |= IPSKB_FRAG_COMPLETE;
|
||||
ll_rs = LL_RESERVED_SPACE(rt->dst.dev);
|
||||
|
||||
@@ -317,7 +317,7 @@ static int ip_tunnel_bind_dev(struct net_device *dev)
|
||||
mtu = min(tdev->mtu, IP_MAX_MTU);
|
||||
}
|
||||
|
||||
dev->needed_headroom = t_hlen + hlen;
|
||||
dev->needed_headroom = ip_tunnel_limit_headroom(t_hlen + hlen);
|
||||
mtu -= t_hlen + (dev->type == ARPHRD_ETHER ? dev->hard_header_len : 0);
|
||||
|
||||
if (mtu < IPV4_MIN_MTU)
|
||||
|
||||
@@ -2213,6 +2213,9 @@ int ip_mr_input(struct sk_buff *skb)
|
||||
if (IPCB(skb)->flags & IPSKB_FORWARDED)
|
||||
goto dont_forward;
|
||||
|
||||
if (!local)
|
||||
skb_orphan(skb);
|
||||
|
||||
mrt = ipmr_rt_fib_lookup(net, skb);
|
||||
if (IS_ERR(mrt)) {
|
||||
kfree_skb(skb);
|
||||
|
||||
@@ -1136,13 +1136,11 @@ static void ip6gre_tnl_link_config_route(struct ip6_tnl *t, int set_mtu,
|
||||
return;
|
||||
|
||||
if (rt->dst.dev) {
|
||||
unsigned short dst_len = rt->dst.dev->hard_header_len +
|
||||
t_hlen;
|
||||
unsigned int headroom;
|
||||
|
||||
if (t->dev->header_ops)
|
||||
dev->hard_header_len = dst_len;
|
||||
else
|
||||
dev->needed_headroom = dst_len;
|
||||
headroom = rt->dst.dev->hard_header_len + t_hlen;
|
||||
headroom = ip_tunnel_limit_headroom(headroom);
|
||||
dev->needed_headroom = headroom;
|
||||
|
||||
if (set_mtu) {
|
||||
int mtu = rt->dst.dev->mtu - t_hlen;
|
||||
@@ -1170,8 +1168,8 @@ static int ip6gre_calc_hlen(struct ip6_tnl *tunnel)
|
||||
|
||||
t_hlen = tunnel->hlen + sizeof(struct ipv6hdr);
|
||||
|
||||
if (tunnel->dev->header_ops)
|
||||
tunnel->dev->hard_header_len = LL_MAX_HEADER + t_hlen;
|
||||
if (tunnel->dev->header_ops && tunnel->dev->type == ARPHRD_IP6GRE)
|
||||
tunnel->dev->hard_header_len = t_hlen;
|
||||
else
|
||||
tunnel->dev->needed_headroom = LL_MAX_HEADER + t_hlen;
|
||||
|
||||
|
||||
@@ -622,6 +622,7 @@ int ip6_mc_input(struct sk_buff *skb)
|
||||
if (deliver) {
|
||||
skb2 = skb_clone(skb, GFP_ATOMIC);
|
||||
} else {
|
||||
skb_orphan(skb);
|
||||
skb2 = skb;
|
||||
skb = NULL;
|
||||
}
|
||||
|
||||
@@ -116,6 +116,8 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *
|
||||
|
||||
if (res != LWTUNNEL_XMIT_CONTINUE)
|
||||
return res;
|
||||
hdr = ipv6_hdr(skb);
|
||||
daddr = &hdr->daddr;
|
||||
}
|
||||
|
||||
IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
|
||||
|
||||
@@ -1236,19 +1236,8 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
|
||||
*/
|
||||
max_headroom += LL_RESERVED_SPACE(tdev);
|
||||
|
||||
if (skb_headroom(skb) < max_headroom || skb_shared(skb) ||
|
||||
(skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
|
||||
struct sk_buff *new_skb;
|
||||
|
||||
new_skb = skb_realloc_headroom(skb, max_headroom);
|
||||
if (!new_skb)
|
||||
goto tx_err_dst_release;
|
||||
|
||||
if (skb->sk)
|
||||
skb_set_owner_w(new_skb, skb->sk);
|
||||
consume_skb(skb);
|
||||
skb = new_skb;
|
||||
}
|
||||
if (skb_cow_head(skb, max_headroom))
|
||||
goto tx_err_dst_release;
|
||||
|
||||
if (t->parms.collect_md) {
|
||||
if (t->encap.type != TUNNEL_ENCAP_NONE)
|
||||
@@ -1525,8 +1514,11 @@ static void ip6_tnl_link_config(struct ip6_tnl *t)
|
||||
tdev = __dev_get_by_index(t->net, p->link);
|
||||
|
||||
if (tdev) {
|
||||
dev->needed_headroom = tdev->hard_header_len +
|
||||
tdev->needed_headroom + t_hlen;
|
||||
unsigned int headroom;
|
||||
|
||||
headroom = tdev->hard_header_len + tdev->needed_headroom;
|
||||
headroom += t_hlen;
|
||||
dev->needed_headroom = ip_tunnel_limit_headroom(headroom);
|
||||
mtu = min_t(unsigned int, tdev->mtu, IP6_MAX_MTU);
|
||||
|
||||
mtu = mtu - t_hlen;
|
||||
|
||||
@@ -1131,7 +1131,7 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev)
|
||||
WRITE_ONCE(dev->mtu, mtu);
|
||||
hlen = tdev->hard_header_len + tdev->needed_headroom;
|
||||
}
|
||||
dev->needed_headroom = t_hlen + hlen;
|
||||
dev->needed_headroom = ip_tunnel_limit_headroom(t_hlen + hlen);
|
||||
}
|
||||
|
||||
static void ipip6_tunnel_update(struct ip_tunnel *t,
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* Copyright (c) 2016 Tom Herbert <tom@herbertland.com>
|
||||
*/
|
||||
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/errqueue.h>
|
||||
@@ -391,7 +392,9 @@ static int kcm_parse_func_strparser(struct strparser *strp, struct sk_buff *skb)
|
||||
struct bpf_prog *prog = psock->bpf_prog;
|
||||
int res;
|
||||
|
||||
rcu_read_lock();
|
||||
res = bpf_prog_run_pin_on_cpu(prog, skb);
|
||||
rcu_read_unlock();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -221,6 +221,7 @@ static u32 mpls_multipath_hash(struct mpls_route *rt, struct sk_buff *skb)
|
||||
if (pskb_may_pull(skb, mpls_hdr_len + sizeof(struct iphdr))) {
|
||||
const struct iphdr *v4hdr;
|
||||
|
||||
hdr = mpls_hdr(skb) + label_index;
|
||||
v4hdr = (const struct iphdr *)(hdr + 1);
|
||||
if (v4hdr->version == 4) {
|
||||
hash = jhash_3words(ntohl(v4hdr->saddr),
|
||||
@@ -231,6 +232,7 @@ static u32 mpls_multipath_hash(struct mpls_route *rt, struct sk_buff *skb)
|
||||
sizeof(struct ipv6hdr))) {
|
||||
const struct ipv6hdr *v6hdr;
|
||||
|
||||
hdr = mpls_hdr(skb) + label_index;
|
||||
v6hdr = (const struct ipv6hdr *)(hdr + 1);
|
||||
hash = __ipv6_addr_jhash(&v6hdr->saddr, hash);
|
||||
hash = __ipv6_addr_jhash(&v6hdr->daddr, hash);
|
||||
|
||||
@@ -127,7 +127,7 @@ static void digital_wq_cmd_complete(struct work_struct *work)
|
||||
|
||||
mutex_unlock(&ddev->cmd_lock);
|
||||
|
||||
if (!IS_ERR(cmd->resp))
|
||||
if (!IS_ERR_OR_NULL(cmd->resp))
|
||||
print_hex_dump_debug("DIGITAL RX: ", DUMP_PREFIX_NONE, 16, 1,
|
||||
cmd->resp->data, cmd->resp->len, false);
|
||||
|
||||
|
||||
@@ -778,6 +778,8 @@ static void digital_in_recv_sensf_res(struct nfc_digital_dev *ddev, void *arg,
|
||||
|
||||
sensf_res = (struct digital_sensf_res *)resp->data;
|
||||
|
||||
resp->len = min_t(unsigned int, resp->len, NFC_SENSF_RES_MAXSIZE);
|
||||
|
||||
memcpy(target.sensf_res, sensf_res, resp->len);
|
||||
target.sensf_res_len = resp->len;
|
||||
|
||||
|
||||
@@ -193,7 +193,8 @@ int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local,
|
||||
const u8 *tlv_array, u16 tlv_array_len)
|
||||
{
|
||||
const u8 *tlv = tlv_array;
|
||||
u8 type, length, offset = 0;
|
||||
u8 type, length;
|
||||
u16 offset = 0;
|
||||
|
||||
pr_debug("TLV array length %d\n", tlv_array_len);
|
||||
|
||||
@@ -201,9 +202,15 @@ int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local,
|
||||
return -ENODEV;
|
||||
|
||||
while (offset < tlv_array_len) {
|
||||
if (offset + 2 > tlv_array_len)
|
||||
return -EINVAL;
|
||||
|
||||
type = tlv[0];
|
||||
length = tlv[1];
|
||||
|
||||
if (offset + 2 + length > tlv_array_len)
|
||||
return -EINVAL;
|
||||
|
||||
pr_debug("type 0x%x length %d\n", type, length);
|
||||
|
||||
switch (type) {
|
||||
@@ -243,7 +250,8 @@ int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
|
||||
const u8 *tlv_array, u16 tlv_array_len)
|
||||
{
|
||||
const u8 *tlv = tlv_array;
|
||||
u8 type, length, offset = 0;
|
||||
u8 type, length;
|
||||
u16 offset = 0;
|
||||
|
||||
pr_debug("TLV array length %d\n", tlv_array_len);
|
||||
|
||||
@@ -251,9 +259,15 @@ int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
|
||||
return -ENOTCONN;
|
||||
|
||||
while (offset < tlv_array_len) {
|
||||
if (offset + 2 > tlv_array_len)
|
||||
return -EINVAL;
|
||||
|
||||
type = tlv[0];
|
||||
length = tlv[1];
|
||||
|
||||
if (offset + 2 + length > tlv_array_len)
|
||||
return -EINVAL;
|
||||
|
||||
pr_debug("type 0x%x length %d\n", type, length);
|
||||
|
||||
switch (type) {
|
||||
|
||||
@@ -849,13 +849,16 @@ static struct nfc_llcp_sock *nfc_llcp_sock_get_sn(struct nfc_llcp_local *local,
|
||||
static const u8 *nfc_llcp_connect_sn(const struct sk_buff *skb, size_t *sn_len)
|
||||
{
|
||||
u8 type, length;
|
||||
const u8 *tlv = &skb->data[2];
|
||||
size_t tlv_array_len = skb->len - LLCP_HEADER_SIZE, offset = 0;
|
||||
const u8 *tlv = &skb->data[LLCP_HEADER_SIZE];
|
||||
const u8 *tlv_end = skb_tail_pointer(skb);
|
||||
|
||||
while (offset < tlv_array_len) {
|
||||
while (tlv + 2 < tlv_end) {
|
||||
type = tlv[0];
|
||||
length = tlv[1];
|
||||
|
||||
if (tlv + 2 + length > tlv_end)
|
||||
break;
|
||||
|
||||
pr_debug("type 0x%x length %d\n", type, length);
|
||||
|
||||
if (type == LLCP_TLV_SN) {
|
||||
@@ -863,7 +866,6 @@ static const u8 *nfc_llcp_connect_sn(const struct sk_buff *skb, size_t *sn_len)
|
||||
return &tlv[2];
|
||||
}
|
||||
|
||||
offset += length + 2;
|
||||
tlv += length + 2;
|
||||
}
|
||||
|
||||
@@ -1286,10 +1288,9 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
|
||||
{
|
||||
struct nfc_llcp_sock *llcp_sock;
|
||||
u8 dsap, ssap, type, length, tid, sap;
|
||||
const u8 *tlv;
|
||||
u16 tlv_len, offset;
|
||||
const u8 *tlv, *tlv_end;
|
||||
const char *service_name;
|
||||
size_t service_name_len;
|
||||
int service_name_len;
|
||||
struct nfc_llcp_sdp_tlv *sdp;
|
||||
HLIST_HEAD(llc_sdres_list);
|
||||
size_t sdres_tlvs_len;
|
||||
@@ -1305,22 +1306,34 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Walk the SNL TLV list in the linear part of the skb only,
|
||||
* bounded by skb_tail_pointer(). Each TLV needs a two-byte
|
||||
* header (type, length) and its declared length must fit before
|
||||
* the end; this also keeps the walk safe for very short frames.
|
||||
*/
|
||||
tlv = &skb->data[LLCP_HEADER_SIZE];
|
||||
tlv_len = skb->len - LLCP_HEADER_SIZE;
|
||||
offset = 0;
|
||||
tlv_end = skb_tail_pointer(skb);
|
||||
sdres_tlvs_len = 0;
|
||||
|
||||
while (offset < tlv_len) {
|
||||
while (tlv + 2 < tlv_end) {
|
||||
type = tlv[0];
|
||||
length = tlv[1];
|
||||
|
||||
if (tlv + 2 + length > tlv_end)
|
||||
break;
|
||||
|
||||
switch (type) {
|
||||
case LLCP_TLV_SDREQ:
|
||||
if (length < 1)
|
||||
break;
|
||||
|
||||
tid = tlv[2];
|
||||
service_name = (char *) &tlv[3];
|
||||
service_name_len = length - 1;
|
||||
|
||||
pr_debug("Looking for %.16s\n", service_name);
|
||||
pr_debug("Looking for %.*s\n", service_name_len,
|
||||
service_name);
|
||||
|
||||
if (service_name_len == strlen("urn:nfc:sn:sdp") &&
|
||||
!strncmp(service_name, "urn:nfc:sn:sdp",
|
||||
@@ -1380,6 +1393,9 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
|
||||
break;
|
||||
|
||||
case LLCP_TLV_SDRES:
|
||||
if (length != 2)
|
||||
break;
|
||||
|
||||
mutex_lock(&local->sdreq_lock);
|
||||
|
||||
pr_debug("LLCP_TLV_SDRES: searching tid %d\n", tlv[2]);
|
||||
@@ -1408,7 +1424,6 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
|
||||
break;
|
||||
}
|
||||
|
||||
offset += length + 2;
|
||||
tlv += length + 2;
|
||||
}
|
||||
|
||||
@@ -1552,6 +1567,11 @@ static void nfc_llcp_rx_work(struct work_struct *work)
|
||||
|
||||
static void __nfc_llcp_recv(struct nfc_llcp_local *local, struct sk_buff *skb)
|
||||
{
|
||||
if (!pskb_may_pull(skb, LLCP_HEADER_SIZE)) {
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
local->rx_pending = skb;
|
||||
timer_delete(&local->link_timer);
|
||||
schedule_work(&local->rx_work);
|
||||
|
||||
@@ -319,14 +319,22 @@ static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname,
|
||||
if (get_user(len, optlen))
|
||||
return -EFAULT;
|
||||
|
||||
local = llcp_sock->local;
|
||||
if (!local)
|
||||
return -ENODEV;
|
||||
if (len < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (len < sizeof(u32))
|
||||
return -EINVAL;
|
||||
|
||||
len = min_t(u32, len, sizeof(u32));
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
local = llcp_sock->local;
|
||||
if (!local) {
|
||||
release_sock(sk);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
switch (optname) {
|
||||
case NFC_LLCP_RW:
|
||||
rw = llcp_sock->rw > LLCP_MAX_RW ? local->rw : llcp_sock->rw;
|
||||
|
||||
@@ -46,11 +46,11 @@ void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
|
||||
timer_delete_sync(&ndev->data_timer);
|
||||
clear_bit(NCI_DATA_EXCHANGE_TO, &ndev->flags);
|
||||
|
||||
/* Mark the exchange as done before calling the callback.
|
||||
* The callback (e.g. rawsock_data_exchange_complete) may
|
||||
* want to immediately queue another data exchange.
|
||||
*/
|
||||
clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
|
||||
/* Claim completion atomically -- both close and rx_work may race here */
|
||||
if (!test_and_clear_bit(NCI_DATA_EXCHANGE, &ndev->flags)) {
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cb) {
|
||||
/* forward skb to nfc core */
|
||||
|
||||
@@ -440,7 +440,7 @@ void nci_clear_target_list(struct nci_dev *ndev)
|
||||
static int nci_rf_discover_ntf_packet(struct nci_dev *ndev,
|
||||
const struct sk_buff *skb)
|
||||
{
|
||||
struct nci_rf_discover_ntf ntf;
|
||||
struct nci_rf_discover_ntf ntf = {};
|
||||
const __u8 *data;
|
||||
bool add_target = true;
|
||||
|
||||
@@ -525,15 +525,19 @@ static int nci_rf_discover_ntf_packet(struct nci_dev *ndev,
|
||||
|
||||
static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev,
|
||||
struct nci_rf_intf_activated_ntf *ntf,
|
||||
const __u8 *data)
|
||||
const __u8 *data, __u8 data_len)
|
||||
{
|
||||
struct activation_params_nfca_poll_iso_dep *nfca_poll;
|
||||
struct activation_params_nfcb_poll_iso_dep *nfcb_poll;
|
||||
|
||||
switch (ntf->activation_rf_tech_and_mode) {
|
||||
case NCI_NFC_A_PASSIVE_POLL_MODE:
|
||||
if (data_len < 1)
|
||||
return NCI_STATUS_RF_PROTOCOL_ERROR;
|
||||
nfca_poll = &ntf->activation_params.nfca_poll_iso_dep;
|
||||
nfca_poll->rats_res_len = min_t(__u8, *data++, NFC_ATS_MAXSIZE);
|
||||
data_len--;
|
||||
nfca_poll->rats_res_len = min_t(__u8, nfca_poll->rats_res_len, data_len);
|
||||
pr_debug("rats_res_len %d\n", nfca_poll->rats_res_len);
|
||||
if (nfca_poll->rats_res_len > 0) {
|
||||
memcpy(nfca_poll->rats_res,
|
||||
@@ -542,8 +546,12 @@ static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev,
|
||||
break;
|
||||
|
||||
case NCI_NFC_B_PASSIVE_POLL_MODE:
|
||||
if (data_len < 1)
|
||||
return NCI_STATUS_RF_PROTOCOL_ERROR;
|
||||
nfcb_poll = &ntf->activation_params.nfcb_poll_iso_dep;
|
||||
nfcb_poll->attrib_res_len = min_t(__u8, *data++, 50);
|
||||
data_len--;
|
||||
nfcb_poll->attrib_res_len = min_t(__u8, nfcb_poll->attrib_res_len, data_len);
|
||||
pr_debug("attrib_res_len %d\n", nfcb_poll->attrib_res_len);
|
||||
if (nfcb_poll->attrib_res_len > 0) {
|
||||
memcpy(nfcb_poll->attrib_res,
|
||||
@@ -562,7 +570,7 @@ static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev,
|
||||
|
||||
static int nci_extract_activation_params_nfc_dep(struct nci_dev *ndev,
|
||||
struct nci_rf_intf_activated_ntf *ntf,
|
||||
const __u8 *data)
|
||||
const __u8 *data, __u8 data_len)
|
||||
{
|
||||
struct activation_params_poll_nfc_dep *poll;
|
||||
struct activation_params_listen_nfc_dep *listen;
|
||||
@@ -570,9 +578,13 @@ static int nci_extract_activation_params_nfc_dep(struct nci_dev *ndev,
|
||||
switch (ntf->activation_rf_tech_and_mode) {
|
||||
case NCI_NFC_A_PASSIVE_POLL_MODE:
|
||||
case NCI_NFC_F_PASSIVE_POLL_MODE:
|
||||
if (data_len < 1)
|
||||
return NCI_STATUS_RF_PROTOCOL_ERROR;
|
||||
poll = &ntf->activation_params.poll_nfc_dep;
|
||||
poll->atr_res_len = min_t(__u8, *data++,
|
||||
NFC_ATR_RES_MAXSIZE - 2);
|
||||
data_len--;
|
||||
poll->atr_res_len = min_t(__u8, poll->atr_res_len, data_len);
|
||||
pr_debug("atr_res_len %d\n", poll->atr_res_len);
|
||||
if (poll->atr_res_len > 0)
|
||||
memcpy(poll->atr_res, data, poll->atr_res_len);
|
||||
@@ -580,9 +592,13 @@ static int nci_extract_activation_params_nfc_dep(struct nci_dev *ndev,
|
||||
|
||||
case NCI_NFC_A_PASSIVE_LISTEN_MODE:
|
||||
case NCI_NFC_F_PASSIVE_LISTEN_MODE:
|
||||
if (data_len < 1)
|
||||
return NCI_STATUS_RF_PROTOCOL_ERROR;
|
||||
listen = &ntf->activation_params.listen_nfc_dep;
|
||||
listen->atr_req_len = min_t(__u8, *data++,
|
||||
NFC_ATR_REQ_MAXSIZE - 2);
|
||||
data_len--;
|
||||
listen->atr_req_len = min_t(__u8, listen->atr_req_len, data_len);
|
||||
pr_debug("atr_req_len %d\n", listen->atr_req_len);
|
||||
if (listen->atr_req_len > 0)
|
||||
memcpy(listen->atr_req, data, listen->atr_req_len);
|
||||
@@ -603,6 +619,12 @@ static void nci_target_auto_activated(struct nci_dev *ndev,
|
||||
struct nfc_target *target;
|
||||
int rc;
|
||||
|
||||
/* This is a new target, check if we've enough room */
|
||||
if (ndev->n_targets == NCI_MAX_DISCOVERED_TARGETS) {
|
||||
pr_debug("not enough room, ignoring new target...\n");
|
||||
return;
|
||||
}
|
||||
|
||||
target = &ndev->targets[ndev->n_targets];
|
||||
|
||||
rc = nci_add_new_protocol(ndev, target, ntf->rf_protocol,
|
||||
@@ -688,7 +710,7 @@ static int nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
|
||||
const struct sk_buff *skb)
|
||||
{
|
||||
struct nci_conn_info *conn_info;
|
||||
struct nci_rf_intf_activated_ntf ntf;
|
||||
struct nci_rf_intf_activated_ntf ntf = {};
|
||||
const __u8 *data;
|
||||
int err = NCI_STATUS_OK;
|
||||
|
||||
@@ -806,12 +828,14 @@ static int nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
|
||||
switch (ntf.rf_interface) {
|
||||
case NCI_RF_INTERFACE_ISO_DEP:
|
||||
err = nci_extract_activation_params_iso_dep(ndev,
|
||||
&ntf, data);
|
||||
&ntf, data,
|
||||
ntf.activation_params_len);
|
||||
break;
|
||||
|
||||
case NCI_RF_INTERFACE_NFC_DEP:
|
||||
err = nci_extract_activation_params_nfc_dep(ndev,
|
||||
&ntf, data);
|
||||
&ntf, data,
|
||||
ntf.activation_params_len);
|
||||
break;
|
||||
|
||||
case NCI_RF_INTERFACE_FRAME:
|
||||
|
||||
@@ -50,11 +50,27 @@ static u8 nci_core_init_rsp_packet_v1(struct nci_dev *ndev,
|
||||
const struct nci_core_init_rsp_1 *rsp_1 = (void *)skb->data;
|
||||
const struct nci_core_init_rsp_2 *rsp_2;
|
||||
|
||||
/* Ensure that the status field can be accessed. */
|
||||
if (skb_headlen(skb) < 1)
|
||||
return NCI_STATUS_SYNTAX_ERROR;
|
||||
|
||||
pr_debug("status 0x%x\n", rsp_1->status);
|
||||
|
||||
if (rsp_1->status != NCI_STATUS_OK)
|
||||
return rsp_1->status;
|
||||
|
||||
/* Success response must contain the full fixed-size header */
|
||||
if (skb_headlen(skb) < sizeof(*rsp_1))
|
||||
return NCI_STATUS_SYNTAX_ERROR;
|
||||
|
||||
/* Ensure the variable-length rf_interfaces array and trailing
|
||||
* rsp_2 structure are fully contained within the skb.
|
||||
*/
|
||||
if (skb_headlen(skb) < sizeof(*rsp_1) +
|
||||
rsp_1->num_supported_rf_interfaces +
|
||||
sizeof(*rsp_2))
|
||||
return NCI_STATUS_SYNTAX_ERROR;
|
||||
|
||||
ndev->nfcc_features = __le32_to_cpu(rsp_1->nfcc_features);
|
||||
ndev->num_supported_rf_interfaces = rsp_1->num_supported_rf_interfaces;
|
||||
|
||||
@@ -87,15 +103,25 @@ static u8 nci_core_init_rsp_packet_v2(struct nci_dev *ndev,
|
||||
const struct sk_buff *skb)
|
||||
{
|
||||
const struct nci_core_init_rsp_nci_ver2 *rsp = (void *)skb->data;
|
||||
const u8 *supported_rf_interface = rsp->supported_rf_interfaces;
|
||||
const u8 *supported_rf_interface;
|
||||
u8 rf_interface_idx = 0;
|
||||
u8 rf_extension_cnt = 0;
|
||||
|
||||
/* Ensure that the status field can be accessed. */
|
||||
if (skb_headlen(skb) < 1)
|
||||
return NCI_STATUS_SYNTAX_ERROR;
|
||||
|
||||
pr_debug("status %x\n", rsp->status);
|
||||
|
||||
if (rsp->status != NCI_STATUS_OK)
|
||||
return rsp->status;
|
||||
|
||||
/* Success response must contain the full fixed-size header */
|
||||
if (skb_headlen(skb) < sizeof(*rsp))
|
||||
return NCI_STATUS_SYNTAX_ERROR;
|
||||
|
||||
supported_rf_interface = rsp->supported_rf_interfaces;
|
||||
|
||||
ndev->nfcc_features = __le32_to_cpu(rsp->nfcc_features);
|
||||
ndev->num_supported_rf_interfaces = rsp->num_supported_rf_interfaces;
|
||||
|
||||
@@ -104,13 +130,22 @@ static u8 nci_core_init_rsp_packet_v2(struct nci_dev *ndev,
|
||||
NCI_MAX_SUPPORTED_RF_INTERFACES);
|
||||
|
||||
while (rf_interface_idx < ndev->num_supported_rf_interfaces) {
|
||||
ndev->supported_rf_interfaces[rf_interface_idx++] = *supported_rf_interface++;
|
||||
/* Each entry: [rf_interface_type (1B)] [ext_count (1B)] [ext...] */
|
||||
if (supported_rf_interface + 2 > skb_tail_pointer(skb))
|
||||
break;
|
||||
ndev->supported_rf_interfaces[rf_interface_idx] = *supported_rf_interface++;
|
||||
|
||||
/* skip rf extension parameters */
|
||||
rf_extension_cnt = *supported_rf_interface++;
|
||||
if (supported_rf_interface + rf_extension_cnt > skb_tail_pointer(skb))
|
||||
break;
|
||||
|
||||
/* Only count the entry after full validation */
|
||||
rf_interface_idx++;
|
||||
supported_rf_interface += rf_extension_cnt;
|
||||
}
|
||||
|
||||
ndev->num_supported_rf_interfaces = rf_interface_idx;
|
||||
|
||||
ndev->max_logical_connections = rsp->max_logical_connections;
|
||||
ndev->max_routing_table_size =
|
||||
__le16_to_cpu(rsp->max_routing_table_size);
|
||||
@@ -336,6 +371,7 @@ static void nci_core_conn_close_rsp_packet(struct nci_dev *ndev,
|
||||
list_del(&conn_info->list);
|
||||
if (conn_info == ndev->rf_conn_info)
|
||||
ndev->rf_conn_info = NULL;
|
||||
devm_kfree(&ndev->nfc_dev->dev, conn_info->dest_params);
|
||||
devm_kfree(&ndev->nfc_dev->dev, conn_info);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1995,6 +1995,7 @@ int ovs_ct_init(struct net *net)
|
||||
{
|
||||
unsigned int n_bits = sizeof(struct ovs_key_ct_labels) * BITS_PER_BYTE;
|
||||
struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
|
||||
int err = 0;
|
||||
|
||||
if (nf_connlabels_get(net, n_bits - 1)) {
|
||||
ovs_net->xt_label = false;
|
||||
@@ -2004,10 +2005,11 @@ int ovs_ct_init(struct net *net)
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_NETFILTER_CONNCOUNT)
|
||||
return ovs_ct_limit_init(net, ovs_net);
|
||||
#else
|
||||
return 0;
|
||||
err = ovs_ct_limit_init(net, ovs_net);
|
||||
if (err && ovs_net->xt_label)
|
||||
nf_connlabels_put(net);
|
||||
#endif
|
||||
return err;
|
||||
}
|
||||
|
||||
void ovs_ct_exit(struct net *net)
|
||||
|
||||
@@ -1473,33 +1473,34 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
reply = ovs_flow_cmd_alloc_info(ovsl_dereference(flow->sf_acts),
|
||||
&flow->id, info, false, ufid_flags);
|
||||
if (IS_ERR(reply)) {
|
||||
netlink_set_err(sock_net(skb->sk)->genl_sock, 0, 0,
|
||||
PTR_ERR(reply));
|
||||
reply = NULL;
|
||||
}
|
||||
|
||||
if (likely(reply)) {
|
||||
err = ovs_flow_cmd_fill_info(flow, ovs_header->dp_ifindex,
|
||||
reply, info->snd_portid,
|
||||
info->snd_seq, 0,
|
||||
OVS_FLOW_CMD_DEL, ufid_flags);
|
||||
if (WARN_ON_ONCE(err < 0)) {
|
||||
kfree_skb(reply);
|
||||
reply = NULL;
|
||||
}
|
||||
}
|
||||
/* Removal has to happen after ovs_flow_cmd_fill_info(), as it uses
|
||||
* the flow->mask that can be scheduled to be freed by the
|
||||
* ovs_flow_tbl_remove() and we're not holding the RCU read lock.
|
||||
*/
|
||||
ovs_flow_tbl_remove(&dp->table, flow);
|
||||
ovs_unlock();
|
||||
|
||||
reply = ovs_flow_cmd_alloc_info((const struct sw_flow_actions __force *) flow->sf_acts,
|
||||
&flow->id, info, false, ufid_flags);
|
||||
if (likely(reply)) {
|
||||
if (!IS_ERR(reply)) {
|
||||
rcu_read_lock(); /*To keep RCU checker happy. */
|
||||
err = ovs_flow_cmd_fill_info(flow, ovs_header->dp_ifindex,
|
||||
reply, info->snd_portid,
|
||||
info->snd_seq, 0,
|
||||
OVS_FLOW_CMD_DEL,
|
||||
ufid_flags);
|
||||
rcu_read_unlock();
|
||||
if (WARN_ON_ONCE(err < 0)) {
|
||||
kfree_skb(reply);
|
||||
goto out_free;
|
||||
}
|
||||
if (likely(reply))
|
||||
ovs_notify(&dp_flow_genl_family, reply, info);
|
||||
|
||||
ovs_notify(&dp_flow_genl_family, reply, info);
|
||||
} else {
|
||||
netlink_set_err(sock_net(skb->sk)->genl_sock, 0, 0,
|
||||
PTR_ERR(reply));
|
||||
}
|
||||
}
|
||||
|
||||
out_free:
|
||||
ovs_flow_free(flow, true);
|
||||
return 0;
|
||||
unlock:
|
||||
|
||||
@@ -1332,6 +1332,10 @@ static int sctp_cmd_interpreter(enum sctp_event_type event_type,
|
||||
sctp_outq_uncork(&asoc->outqueue, gfp);
|
||||
local_cork = 0;
|
||||
}
|
||||
/* No chunk left in this packet may use this asoc. */
|
||||
if (event_type == SCTP_EVENT_T_CHUNK &&
|
||||
chunk->asoc == asoc)
|
||||
chunk->pdiscard = 1;
|
||||
/* Delete the current association. */
|
||||
sctp_cmd_delete_tcb(commands, asoc);
|
||||
asoc = NULL;
|
||||
|
||||
@@ -409,13 +409,13 @@ void smc_sk_init(struct net *net, struct sock *sk, int protocol)
|
||||
"sk_lock-AF_SMC", &smc_key);
|
||||
spin_lock_init(&smc->accept_q_lock);
|
||||
spin_lock_init(&smc->conn.send_lock);
|
||||
sk->sk_prot->hash(sk);
|
||||
mutex_init(&smc->clcsock_release_lock);
|
||||
smc_init_saved_callbacks(smc);
|
||||
smc->limit_smc_hs = net->smc.limit_smc_hs;
|
||||
smc->use_fallback = false; /* assume rdma capability first */
|
||||
smc->fallback_rsn = 0;
|
||||
smc_close_init(smc);
|
||||
sk->sk_prot->hash(sk);
|
||||
}
|
||||
|
||||
static struct sock *smc_sock_alloc(struct net *net, struct socket *sock,
|
||||
@@ -3233,7 +3233,8 @@ int smc_ioctl(struct socket *sock, unsigned int cmd,
|
||||
return -EINVAL;
|
||||
}
|
||||
if (smc->sk.sk_state == SMC_INIT ||
|
||||
smc->sk.sk_state == SMC_CLOSED)
|
||||
smc->sk.sk_state == SMC_CLOSED ||
|
||||
!READ_ONCE(smc->conn.sndbuf_desc))
|
||||
answ = 0;
|
||||
else
|
||||
answ = smc->conn.sndbuf_desc->len -
|
||||
|
||||
@@ -1209,14 +1209,16 @@ static void smcd_buf_detach(struct smc_connection *conn)
|
||||
{
|
||||
struct smcd_dev *smcd = conn->lgr->smcd;
|
||||
u64 peer_token = conn->peer_token;
|
||||
struct smc_buf_desc *buf_desc;
|
||||
|
||||
if (!conn->sndbuf_desc)
|
||||
return;
|
||||
|
||||
smc_ism_detach_dmb(smcd, peer_token);
|
||||
|
||||
kfree(conn->sndbuf_desc);
|
||||
buf_desc = conn->sndbuf_desc;
|
||||
conn->sndbuf_desc = NULL;
|
||||
kfree(buf_desc);
|
||||
}
|
||||
|
||||
static void smc_buf_unuse(struct smc_connection *conn,
|
||||
@@ -1268,11 +1270,10 @@ void smc_conn_free(struct smc_connection *conn)
|
||||
goto lgr_put;
|
||||
|
||||
if (lgr->is_smcd) {
|
||||
if (!list_empty(&lgr->list))
|
||||
smc_ism_unset_conn(conn);
|
||||
smc_ism_unset_conn(conn);
|
||||
tasklet_kill(&conn->rx_tsklet);
|
||||
if (smc_ism_support_dmb_nocopy(lgr->smcd))
|
||||
smcd_buf_detach(conn);
|
||||
tasklet_kill(&conn->rx_tsklet);
|
||||
} else {
|
||||
smc_cdc_wait_pend_tx_wr(conn);
|
||||
if (current_work() != &conn->abort_work)
|
||||
@@ -1525,12 +1526,12 @@ static void smc_conn_kill(struct smc_connection *conn, bool soft)
|
||||
smc_sk_wake_ups(smc);
|
||||
if (conn->lgr->is_smcd) {
|
||||
smc_ism_unset_conn(conn);
|
||||
if (smc_ism_support_dmb_nocopy(conn->lgr->smcd))
|
||||
smcd_buf_detach(conn);
|
||||
if (soft)
|
||||
tasklet_kill(&conn->rx_tsklet);
|
||||
else
|
||||
tasklet_unlock_wait(&conn->rx_tsklet);
|
||||
if (smc_ism_support_dmb_nocopy(conn->lgr->smcd))
|
||||
smcd_buf_detach(conn);
|
||||
} else {
|
||||
smc_cdc_wait_pend_tx_wr(conn);
|
||||
}
|
||||
|
||||
@@ -20,11 +20,15 @@
|
||||
|
||||
static inline int smc_tx_prepared_sends(struct smc_connection *conn)
|
||||
{
|
||||
struct smc_buf_desc *sndbuf_desc = READ_ONCE(conn->sndbuf_desc);
|
||||
union smc_host_cursor sent, prep;
|
||||
|
||||
if (!sndbuf_desc)
|
||||
return 0;
|
||||
|
||||
smc_curs_copy(&sent, &conn->tx_curs_sent, conn);
|
||||
smc_curs_copy(&prep, &conn->tx_curs_prep, conn);
|
||||
return smc_curs_diff(conn->sndbuf_desc->len, &sent, &prep);
|
||||
return smc_curs_diff(sndbuf_desc->len, &sent, &prep);
|
||||
}
|
||||
|
||||
void smc_tx_pending(struct smc_connection *conn);
|
||||
|
||||
@@ -430,9 +430,10 @@ static int tls_strp_read_copy(struct tls_strparser *strp, bool qshort)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool tls_strp_check_queue_ok(struct tls_strparser *strp)
|
||||
static bool tls_strp_check_queue_ok(struct tls_strparser *strp,
|
||||
unsigned int len)
|
||||
{
|
||||
unsigned int len = strp->stm.offset + strp->stm.full_len;
|
||||
unsigned int remaining = strp->stm.offset + len;
|
||||
struct sk_buff *first, *skb;
|
||||
u32 seq;
|
||||
|
||||
@@ -443,9 +444,9 @@ static bool tls_strp_check_queue_ok(struct tls_strparser *strp)
|
||||
/* Make sure there's no duplicate data in the queue,
|
||||
* and the decrypted status matches.
|
||||
*/
|
||||
while (skb->len < len) {
|
||||
while (skb->len < remaining) {
|
||||
seq += skb->len;
|
||||
len -= skb->len;
|
||||
remaining -= skb->len;
|
||||
skb = skb->next;
|
||||
|
||||
if (TCP_SKB_CB(skb)->seq != seq)
|
||||
@@ -525,6 +526,11 @@ static int tls_strp_read_sock(struct tls_strparser *strp)
|
||||
|
||||
tls_strp_load_anchor_with_queue(strp, inq);
|
||||
if (!strp->stm.full_len) {
|
||||
if (inq < TLS_HEADER_SIZE)
|
||||
return tls_strp_read_copy(strp, true);
|
||||
if (!tls_strp_check_queue_ok(strp, TLS_HEADER_SIZE))
|
||||
return tls_strp_read_copy(strp, false);
|
||||
|
||||
sz = tls_rx_msg_size(strp, strp->anchor);
|
||||
if (sz < 0)
|
||||
return sz;
|
||||
@@ -535,7 +541,7 @@ static int tls_strp_read_sock(struct tls_strparser *strp)
|
||||
return tls_strp_read_copy(strp, true);
|
||||
}
|
||||
|
||||
if (!tls_strp_check_queue_ok(strp))
|
||||
if (!tls_strp_check_queue_ok(strp, strp->stm.full_len))
|
||||
return tls_strp_read_copy(strp, false);
|
||||
|
||||
WRITE_ONCE(strp->msg_ready, 1);
|
||||
|
||||
@@ -38,10 +38,9 @@
|
||||
* pending socket. When that socket reaches the connected state, it is removed
|
||||
* from the listener socket's pending list and enqueued in the listener
|
||||
* socket's accept queue. Callers of accept(2) will accept connected sockets
|
||||
* from the listener socket's accept queue. If the socket cannot be accepted
|
||||
* for some reason then it is marked rejected. Once the connection is
|
||||
* accepted, it is owned by the user process and the responsibility for cleanup
|
||||
* falls with that user process.
|
||||
* from the listener socket's accept queue. Once the connection is accepted,
|
||||
* it is owned by the user process and the responsibility for cleanup falls
|
||||
* with that user process.
|
||||
*
|
||||
* - It is possible that these pending sockets will never reach the connected
|
||||
* state; in fact, we may never receive another packet after the connection
|
||||
@@ -49,9 +48,7 @@
|
||||
* future, after some amount of time passes where a connection should have been
|
||||
* established. This function ensures that the socket is off all lists so it
|
||||
* cannot be retrieved, then drops all references to the socket so it is cleaned
|
||||
* up (sock_put() -> sk_free() -> our sk_destruct implementation). Note this
|
||||
* function will also cleanup rejected sockets, those that reach the connected
|
||||
* state but leave it before they have been accepted.
|
||||
* up (sock_put() -> sk_free() -> our sk_destruct implementation).
|
||||
*
|
||||
* - Lock ordering for pending or accept queue sockets is:
|
||||
*
|
||||
@@ -774,11 +771,10 @@ static void vsock_pending_work(struct work_struct *work)
|
||||
|
||||
if (vsock_is_pending(sk)) {
|
||||
vsock_remove_pending(listener, sk);
|
||||
} else if (!vsk->rejected) {
|
||||
/* We are not on the pending list and accept() did not reject
|
||||
* us, so we must have been accepted by our user process. We
|
||||
* just need to drop our references to the sockets and be on
|
||||
* our way.
|
||||
} else {
|
||||
/* We are not on the pending list so we must have been accepted
|
||||
* by our user process. We just need to drop our references to
|
||||
* the sockets and be on our way.
|
||||
*/
|
||||
cleanup = false;
|
||||
goto out;
|
||||
@@ -942,7 +938,6 @@ static struct sock *__vsock_create(struct net *net,
|
||||
vsk->listener = NULL;
|
||||
INIT_LIST_HEAD(&vsk->pending_links);
|
||||
INIT_LIST_HEAD(&vsk->accept_queue);
|
||||
vsk->rejected = false;
|
||||
vsk->sent_request = false;
|
||||
vsk->ignore_connecting_rst = false;
|
||||
WRITE_ONCE(vsk->peer_shutdown, 0);
|
||||
@@ -1847,12 +1842,10 @@ static int vsock_connect(struct socket *sock, struct sockaddr_unsized *addr,
|
||||
prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
|
||||
}
|
||||
|
||||
if (sk->sk_err) {
|
||||
err = -sk->sk_err;
|
||||
err = sock_error(sk);
|
||||
if (err) {
|
||||
sk->sk_state = TCP_CLOSE;
|
||||
sock->state = SS_UNCONNECTED;
|
||||
} else {
|
||||
err = 0;
|
||||
}
|
||||
|
||||
out_wait:
|
||||
@@ -1893,7 +1886,7 @@ static int vsock_accept(struct socket *sock, struct socket *newsock,
|
||||
timeout = sock_rcvtimeo(listener, arg->flags & O_NONBLOCK);
|
||||
|
||||
while ((connected = vsock_dequeue_accept(listener)) == NULL &&
|
||||
listener->sk_err == 0 && timeout != 0) {
|
||||
timeout != 0) {
|
||||
prepare_to_wait(sk_sleep(listener), &wait, TASK_INTERRUPTIBLE);
|
||||
release_sock(listener);
|
||||
timeout = schedule_timeout(timeout);
|
||||
@@ -1906,39 +1899,24 @@ static int vsock_accept(struct socket *sock, struct socket *newsock,
|
||||
}
|
||||
}
|
||||
|
||||
if (listener->sk_err) {
|
||||
err = -listener->sk_err;
|
||||
} else if (!connected) {
|
||||
if (!connected) {
|
||||
err = -EAGAIN;
|
||||
}
|
||||
|
||||
if (connected) {
|
||||
} else {
|
||||
sk_acceptq_removed(listener);
|
||||
|
||||
lock_sock_nested(connected, SINGLE_DEPTH_NESTING);
|
||||
vconnected = vsock_sk(connected);
|
||||
|
||||
/* If the listener socket has received an error, then we should
|
||||
* reject this socket and return. Note that we simply mark the
|
||||
* socket rejected, drop our reference, and let the cleanup
|
||||
* function handle the cleanup; the fact that we found it in
|
||||
* the listener's accept queue guarantees that the cleanup
|
||||
* function hasn't run yet.
|
||||
*/
|
||||
if (err) {
|
||||
vconnected->rejected = true;
|
||||
} else {
|
||||
newsock->state = SS_CONNECTED;
|
||||
sock_graft(connected, newsock);
|
||||
newsock->state = SS_CONNECTED;
|
||||
sock_graft(connected, newsock);
|
||||
|
||||
set_bit(SOCK_CUSTOM_SOCKOPT,
|
||||
set_bit(SOCK_CUSTOM_SOCKOPT,
|
||||
&connected->sk_socket->flags);
|
||||
|
||||
if (vsock_msgzerocopy_allow(vconnected->transport))
|
||||
set_bit(SOCK_SUPPORT_ZC,
|
||||
&connected->sk_socket->flags);
|
||||
|
||||
if (vsock_msgzerocopy_allow(vconnected->transport))
|
||||
set_bit(SOCK_SUPPORT_ZC,
|
||||
&connected->sk_socket->flags);
|
||||
}
|
||||
|
||||
release_sock(connected);
|
||||
sock_put(connected);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user