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

Pull networking fixes from Paolo Abeni:
 "Including fixes from Bluetooth and Wireless. No known outstanding
  regressions.

  Current release - regressions:

   - eth:
      - bonding: fix mii_status when slave is down
      - mlx5e: fix missing error assignment in mlx5e_xfrm_add_state()

  Previous releases - regressions:

   - sched: limit try_bulk_dequeue_skb() batches

   - ipv4: route: prevent rt_bind_exception() from rebinding stale fnhe

   - af_unix: initialise scc_index in unix_add_edge()

   - netpoll: fix incorrect refcount handling causing incorrect cleanup

   - bluetooth: don't hold spin lock over sleeping functions

   - hsr: Fix supervision frame sending on HSRv0

   - sctp: prevent possible shift out-of-bounds

   - tipc: fix use-after-free in tipc_mon_reinit_self().

   - dsa: tag_brcm: do not mark link local traffic as offloaded

   - eth: virtio-net: fix incorrect flags recording in big mode

  Previous releases - always broken:

   - sched: initialize struct tc_ife to fix kernel-infoleak

   - wifi:
      - mac80211: reject address change while connecting
      - iwlwifi: avoid toggling links due to wrong element use

   - bluetooth: cancel mesh send timer when hdev removed

   - strparser: fix signed/unsigned mismatch bug

   - handshake: fix memory leak in tls_handshake_accept()

  Misc:

   - selftests: mptcp: fix some flaky tests"

* tag 'net-6.18-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (60 commits)
  hsr: Follow standard for HSRv0 supervision frames
  hsr: Fix supervision frame sending on HSRv0
  virtio-net: fix incorrect flags recording in big mode
  ipv4: route: Prevent rt_bind_exception() from rebinding stale fnhe
  wifi: iwlwifi: mld: always take beacon ies in link grading
  wifi: iwlwifi: mvm: fix beacon template/fixed rate
  wifi: iwlwifi: fix aux ROC time event iterator usage
  net_sched: limit try_bulk_dequeue_skb() batches
  selftests: mptcp: join: properly kill background tasks
  selftests: mptcp: connect: trunc: read all recv data
  selftests: mptcp: join: userspace: longer transfer
  selftests: mptcp: join: endpoints: longer transfer
  selftests: mptcp: join: rm: set backup flag
  selftests: mptcp: connect: fix fallback note due to OoO
  ethtool: fix incorrect kernel-doc style comment in ethtool.h
  mlx5: Fix default values in create CQ
  Bluetooth: btrtl: Avoid loading the config file on security chips
  net/mlx5e: Fix potentially misleading debug message
  net/mlx5e: Fix wraparound in rate limiting for values above 255 Gbps
  net/mlx5e: Fix maxrate wraparound in threshold between units
  ...
This commit is contained in:
Linus Torvalds
2025-11-13 11:20:25 -08:00
65 changed files with 1206 additions and 316 deletions

View File

@@ -13,10 +13,10 @@ Simple CLI
Kernel comes with a simple CLI tool which should be useful when
developing Netlink related code. The tool is implemented in Python
and can use a YAML specification to issue Netlink requests
to the kernel. Only Generic Netlink is supported.
to the kernel.
The tool is located at ``tools/net/ynl/pyynl/cli.py``. It accepts
a handul of arguments, the most important ones are:
a handful of arguments, the most important ones are:
- ``--spec`` - point to the spec file
- ``--do $name`` / ``--dump $name`` - issue request ``$name``

View File

@@ -50,7 +50,7 @@
#define RTL_CHIP_SUBVER (&(struct rtl_vendor_cmd) {{0x10, 0x38, 0x04, 0x28, 0x80}})
#define RTL_CHIP_REV (&(struct rtl_vendor_cmd) {{0x10, 0x3A, 0x04, 0x28, 0x80}})
#define RTL_SEC_PROJ (&(struct rtl_vendor_cmd) {{0x10, 0xA4, 0x0D, 0x00, 0xb0}})
#define RTL_SEC_PROJ (&(struct rtl_vendor_cmd) {{0x10, 0xA4, 0xAD, 0x00, 0xb0}})
#define RTL_PATCH_SNIPPETS 0x01
#define RTL_PATCH_DUMMY_HEADER 0x02
@@ -534,7 +534,6 @@ static int rtlbt_parse_firmware_v2(struct hci_dev *hdev,
{
struct rtl_epatch_header_v2 *hdr;
int rc;
u8 reg_val[2];
u8 key_id;
u32 num_sections;
struct rtl_section *section;
@@ -549,14 +548,7 @@ static int rtlbt_parse_firmware_v2(struct hci_dev *hdev,
.len = btrtl_dev->fw_len - 7, /* Cut the tail */
};
rc = btrtl_vendor_read_reg16(hdev, RTL_SEC_PROJ, reg_val);
if (rc < 0)
return -EIO;
key_id = reg_val[0];
rtl_dev_dbg(hdev, "%s: key id %u", __func__, key_id);
btrtl_dev->key_id = key_id;
key_id = btrtl_dev->key_id;
hdr = rtl_iov_pull_data(&iov, sizeof(*hdr));
if (!hdr)
@@ -1070,6 +1062,8 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
u16 hci_rev, lmp_subver;
u8 hci_ver, lmp_ver, chip_type = 0;
int ret;
int rc;
u8 key_id;
u8 reg_val[2];
btrtl_dev = kzalloc(sizeof(*btrtl_dev), GFP_KERNEL);
@@ -1180,6 +1174,14 @@ next:
goto err_free;
}
rc = btrtl_vendor_read_reg16(hdev, RTL_SEC_PROJ, reg_val);
if (rc < 0)
goto err_free;
key_id = reg_val[0];
btrtl_dev->key_id = key_id;
rtl_dev_info(hdev, "%s: key id %u", __func__, key_id);
btrtl_dev->fw_len = -EIO;
if (lmp_subver == RTL_ROM_LMP_8852A && hci_rev == 0x000c) {
snprintf(fw_name, sizeof(fw_name), "%s_v2.bin",
@@ -1202,7 +1204,7 @@ next:
goto err_free;
}
if (btrtl_dev->ic_info->cfg_name) {
if (btrtl_dev->ic_info->cfg_name && !btrtl_dev->key_id) {
if (postfix) {
snprintf(cfg_name, sizeof(cfg_name), "%s-%s.bin",
btrtl_dev->ic_info->cfg_name, postfix);

View File

@@ -4361,6 +4361,11 @@ static void btusb_disconnect(struct usb_interface *intf)
hci_unregister_dev(hdev);
if (data->oob_wake_irq)
device_init_wakeup(&data->udev->dev, false);
if (data->reset_gpio)
gpiod_put(data->reset_gpio);
if (intf == data->intf) {
if (data->isoc)
usb_driver_release_interface(&btusb_driver, data->isoc);
@@ -4371,17 +4376,11 @@ static void btusb_disconnect(struct usb_interface *intf)
usb_driver_release_interface(&btusb_driver, data->diag);
usb_driver_release_interface(&btusb_driver, data->intf);
} else if (intf == data->diag) {
usb_driver_release_interface(&btusb_driver, data->intf);
if (data->isoc)
usb_driver_release_interface(&btusb_driver, data->isoc);
usb_driver_release_interface(&btusb_driver, data->intf);
}
if (data->oob_wake_irq)
device_init_wakeup(&data->udev->dev, false);
if (data->reset_gpio)
gpiod_put(data->reset_gpio);
hci_free_dev(hdev);
}

View File

@@ -1020,15 +1020,18 @@ int mlx5_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
if (cq->create_flags & IB_UVERBS_CQ_FLAGS_IGNORE_OVERRUN)
MLX5_SET(cqc, cqc, oi, 1);
if (udata) {
cq->mcq.comp = mlx5_add_cq_to_tasklet;
cq->mcq.tasklet_ctx.comp = mlx5_ib_cq_comp;
} else {
cq->mcq.comp = mlx5_ib_cq_comp;
}
err = mlx5_core_create_cq(dev->mdev, &cq->mcq, cqb, inlen, out, sizeof(out));
if (err)
goto err_cqb;
mlx5_ib_dbg(dev, "cqn 0x%x\n", cq->mcq.cqn);
if (udata)
cq->mcq.tasklet_ctx.comp = mlx5_ib_cq_comp;
else
cq->mcq.comp = mlx5_ib_cq_comp;
cq->mcq.event = mlx5_ib_cq_event;
INIT_LIST_HEAD(&cq->wc_list);

View File

@@ -2120,7 +2120,7 @@ skip_mac_set:
/* check for initial state */
new_slave->link = BOND_LINK_NOCHANGE;
if (bond->params.miimon) {
if (netif_carrier_ok(slave_dev)) {
if (netif_running(slave_dev) && netif_carrier_ok(slave_dev)) {
if (bond->params.updelay) {
bond_set_slave_link_state(new_slave,
BOND_LINK_BACK,
@@ -2665,7 +2665,8 @@ static int bond_miimon_inspect(struct bonding *bond)
bond_for_each_slave_rcu(bond, slave, iter) {
bond_propose_link_state(slave, BOND_LINK_NOCHANGE);
link_state = netif_carrier_ok(slave->dev);
link_state = netif_running(slave->dev) &&
netif_carrier_ok(slave->dev);
switch (slave->link) {
case BOND_LINK_UP:

View File

@@ -1835,6 +1835,8 @@ fec_enet_rx_queue(struct net_device *ndev, u16 queue_id, int budget)
ndev->stats.rx_packets++;
pkt_len = fec16_to_cpu(bdp->cbd_datlen);
ndev->stats.rx_bytes += pkt_len;
if (fep->quirks & FEC_QUIRK_HAS_RACC)
ndev->stats.rx_bytes -= 2;
index = fec_enet_get_bd_index(bdp, &rxq->bd);
page = rxq->rx_skb_info[index].page;

View File

@@ -66,8 +66,8 @@ void mlx5_cq_tasklet_cb(struct tasklet_struct *t)
tasklet_schedule(&ctx->task);
}
static void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq,
struct mlx5_eqe *eqe)
void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq,
struct mlx5_eqe *eqe)
{
unsigned long flags;
struct mlx5_eq_tasklet *tasklet_ctx = cq->tasklet_ctx.priv;
@@ -95,7 +95,15 @@ static void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq,
if (schedule_tasklet)
tasklet_schedule(&tasklet_ctx->task);
}
EXPORT_SYMBOL(mlx5_add_cq_to_tasklet);
static void mlx5_core_cq_dummy_cb(struct mlx5_core_cq *cq, struct mlx5_eqe *eqe)
{
mlx5_core_err(cq->eq->core.dev,
"CQ default completion callback, CQ #%u\n", cq->cqn);
}
#define MLX5_CQ_INIT_CMD_SN cpu_to_be32(2 << 28)
/* Callers must verify outbox status in case of err */
int mlx5_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
u32 *in, int inlen, u32 *out, int outlen)
@@ -121,10 +129,19 @@ int mlx5_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
cq->arm_sn = 0;
cq->eq = eq;
cq->uid = MLX5_GET(create_cq_in, in, uid);
/* Kernel CQs must set the arm_db address prior to calling
* this function, allowing for the proper value to be
* initialized. User CQs are responsible for their own
* initialization since they do not use the arm_db field.
*/
if (cq->arm_db)
*cq->arm_db = MLX5_CQ_INIT_CMD_SN;
refcount_set(&cq->refcount, 1);
init_completion(&cq->free);
if (!cq->comp)
cq->comp = mlx5_add_cq_to_tasklet;
cq->comp = mlx5_core_cq_dummy_cb;
/* assuming CQ will be deleted before the EQ */
cq->tasklet_ctx.priv = &eq->tasklet_ctx;
INIT_LIST_HEAD(&cq->tasklet_ctx.list);

View File

@@ -541,7 +541,7 @@ static int mlx5_devlink_num_doorbells_validate(struct devlink *devlink, u32 id,
max_num_channels = mlx5e_get_max_num_channels(mdev);
if (val32 > max_num_channels) {
NL_SET_ERR_MSG_FMT_MOD(extack,
"Requested num_doorbells (%u) exceeds maximum number of channels (%u)",
"Requested num_doorbells (%u) exceeds max number of channels (%u)",
val32, max_num_channels);
return -EINVAL;
}

View File

@@ -804,7 +804,8 @@ static int mlx5e_xfrm_add_state(struct net_device *dev,
goto err_xfrm;
}
if (mlx5_eswitch_block_mode(priv->mdev))
err = mlx5_eswitch_block_mode(priv->mdev);
if (err)
goto unblock_ipsec;
if (x->props.mode == XFRM_MODE_TUNNEL &&

View File

@@ -595,32 +595,55 @@ static int mlx5e_dcbnl_ieee_setmaxrate(struct net_device *netdev,
struct mlx5_core_dev *mdev = priv->mdev;
u8 max_bw_value[IEEE_8021QAZ_MAX_TCS];
u8 max_bw_unit[IEEE_8021QAZ_MAX_TCS];
__u64 upper_limit_mbps = roundup(255 * MLX5E_100MB, MLX5E_1GB);
__u64 upper_limit_mbps;
__u64 upper_limit_gbps;
int i;
struct {
int scale;
const char *units_str;
} units[] = {
[MLX5_100_MBPS_UNIT] = {
.scale = 100,
.units_str = "Mbps",
},
[MLX5_GBPS_UNIT] = {
.scale = 1,
.units_str = "Gbps",
},
};
memset(max_bw_value, 0, sizeof(max_bw_value));
memset(max_bw_unit, 0, sizeof(max_bw_unit));
upper_limit_mbps = 255 * MLX5E_100MB;
upper_limit_gbps = 255 * MLX5E_1GB;
for (i = 0; i <= mlx5_max_tc(mdev); i++) {
if (!maxrate->tc_maxrate[i]) {
max_bw_unit[i] = MLX5_BW_NO_LIMIT;
continue;
}
if (maxrate->tc_maxrate[i] < upper_limit_mbps) {
if (maxrate->tc_maxrate[i] <= upper_limit_mbps) {
max_bw_value[i] = div_u64(maxrate->tc_maxrate[i],
MLX5E_100MB);
max_bw_value[i] = max_bw_value[i] ? max_bw_value[i] : 1;
max_bw_unit[i] = MLX5_100_MBPS_UNIT;
} else {
} else if (max_bw_value[i] <= upper_limit_gbps) {
max_bw_value[i] = div_u64(maxrate->tc_maxrate[i],
MLX5E_1GB);
max_bw_unit[i] = MLX5_GBPS_UNIT;
} else {
netdev_err(netdev,
"tc_%d maxrate %llu Kbps exceeds limit %llu\n",
i, maxrate->tc_maxrate[i],
upper_limit_gbps);
return -EINVAL;
}
}
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
netdev_dbg(netdev, "%s: tc_%d <=> max_bw %d Gbps\n",
__func__, i, max_bw_value[i]);
netdev_dbg(netdev, "%s: tc_%d <=> max_bw %u %s\n", __func__, i,
max_bw_value[i] * units[max_bw_unit[i]].scale,
units[max_bw_unit[i]].units_str);
}
return mlx5_modify_port_ets_rate_limit(mdev, max_bw_value, max_bw_unit);

View File

@@ -2219,7 +2219,6 @@ static int mlx5e_alloc_cq_common(struct mlx5_core_dev *mdev,
mcq->set_ci_db = cq->wq_ctrl.db.db;
mcq->arm_db = cq->wq_ctrl.db.db + 1;
*mcq->set_ci_db = 0;
*mcq->arm_db = 0;
mcq->vector = param->eq_ix;
mcq->comp = mlx5e_completion_event;
mcq->event = mlx5e_cq_error_event;

View File

@@ -421,6 +421,13 @@ static int mlx5_fpga_conn_create_cq(struct mlx5_fpga_conn *conn, int cq_size)
__be64 *pas;
u32 i;
conn->cq.mcq.cqe_sz = 64;
conn->cq.mcq.set_ci_db = conn->cq.wq_ctrl.db.db;
conn->cq.mcq.arm_db = conn->cq.wq_ctrl.db.db + 1;
*conn->cq.mcq.set_ci_db = 0;
conn->cq.mcq.vector = 0;
conn->cq.mcq.comp = mlx5_fpga_conn_cq_complete;
cq_size = roundup_pow_of_two(cq_size);
MLX5_SET(cqc, temp_cqc, log_cq_size, ilog2(cq_size));
@@ -468,15 +475,7 @@ static int mlx5_fpga_conn_create_cq(struct mlx5_fpga_conn *conn, int cq_size)
if (err)
goto err_cqwq;
conn->cq.mcq.cqe_sz = 64;
conn->cq.mcq.set_ci_db = conn->cq.wq_ctrl.db.db;
conn->cq.mcq.arm_db = conn->cq.wq_ctrl.db.db + 1;
*conn->cq.mcq.set_ci_db = 0;
*conn->cq.mcq.arm_db = 0;
conn->cq.mcq.vector = 0;
conn->cq.mcq.comp = mlx5_fpga_conn_cq_complete;
tasklet_setup(&conn->cq.tasklet, mlx5_fpga_conn_cq_tasklet);
mlx5_fpga_dbg(fdev, "Created CQ #0x%x\n", conn->cq.mcq.cqn);
goto out;

View File

@@ -873,12 +873,6 @@ err_free_sqc:
return err;
}
static void hws_cq_complete(struct mlx5_core_cq *mcq,
struct mlx5_eqe *eqe)
{
pr_err("CQ completion CQ: #%u\n", mcq->cqn);
}
static int hws_send_ring_alloc_cq(struct mlx5_core_dev *mdev,
int numa_node,
struct mlx5hws_send_engine *queue,
@@ -901,7 +895,6 @@ static int hws_send_ring_alloc_cq(struct mlx5_core_dev *mdev,
mcq->cqe_sz = 64;
mcq->set_ci_db = cq->wq_ctrl.db.db;
mcq->arm_db = cq->wq_ctrl.db.db + 1;
mcq->comp = hws_cq_complete;
for (i = 0; i < mlx5_cqwq_get_size(&cq->wq); i++) {
cqe = mlx5_cqwq_get_wqe(&cq->wq, i);

View File

@@ -1049,12 +1049,6 @@ static int dr_prepare_qp_to_rts(struct mlx5dr_domain *dmn)
return 0;
}
static void dr_cq_complete(struct mlx5_core_cq *mcq,
struct mlx5_eqe *eqe)
{
pr_err("CQ completion CQ: #%u\n", mcq->cqn);
}
static struct mlx5dr_cq *dr_create_cq(struct mlx5_core_dev *mdev,
struct mlx5_uars_page *uar,
size_t ncqe)
@@ -1089,6 +1083,13 @@ static struct mlx5dr_cq *dr_create_cq(struct mlx5_core_dev *mdev,
cqe->op_own = MLX5_CQE_INVALID << 4 | MLX5_CQE_OWNER_MASK;
}
cq->mcq.cqe_sz = 64;
cq->mcq.set_ci_db = cq->wq_ctrl.db.db;
cq->mcq.arm_db = cq->wq_ctrl.db.db + 1;
*cq->mcq.set_ci_db = 0;
cq->mcq.vector = 0;
cq->mdev = mdev;
inlen = MLX5_ST_SZ_BYTES(create_cq_in) +
sizeof(u64) * cq->wq_ctrl.buf.npages;
in = kvzalloc(inlen, GFP_KERNEL);
@@ -1112,27 +1113,12 @@ static struct mlx5dr_cq *dr_create_cq(struct mlx5_core_dev *mdev,
pas = (__be64 *)MLX5_ADDR_OF(create_cq_in, in, pas);
mlx5_fill_page_frag_array(&cq->wq_ctrl.buf, pas);
cq->mcq.comp = dr_cq_complete;
err = mlx5_core_create_cq(mdev, &cq->mcq, in, inlen, out, sizeof(out));
kvfree(in);
if (err)
goto err_cqwq;
cq->mcq.cqe_sz = 64;
cq->mcq.set_ci_db = cq->wq_ctrl.db.db;
cq->mcq.arm_db = cq->wq_ctrl.db.db + 1;
*cq->mcq.set_ci_db = 0;
/* set no-zero value, in order to avoid the HW to run db-recovery on
* CQ that used in polling mode.
*/
*cq->mcq.arm_db = cpu_to_be32(2 << 28);
cq->mcq.vector = 0;
cq->mdev = mdev;
return cq;
err_cqwq:

View File

@@ -276,9 +276,31 @@ static int am65_cpsw_iet_set_verify_timeout_count(struct am65_cpsw_port *port)
/* The number of wireside clocks contained in the verify
* timeout counter. The default is 0x1312d0
* (10ms at 125Mhz in 1G mode).
* The frequency of the clock depends on the link speed
* and the PHY interface.
*/
val = 125 * HZ_PER_MHZ; /* assuming 125MHz wireside clock */
switch (port->slave.phy_if) {
case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_TXID:
if (port->qos.link_speed == SPEED_1000)
val = 125 * HZ_PER_MHZ; /* 125 MHz at 1000Mbps*/
else if (port->qos.link_speed == SPEED_100)
val = 25 * HZ_PER_MHZ; /* 25 MHz at 100Mbps*/
else
val = (25 * HZ_PER_MHZ) / 10; /* 2.5 MHz at 10Mbps*/
break;
case PHY_INTERFACE_MODE_QSGMII:
case PHY_INTERFACE_MODE_SGMII:
val = 125 * HZ_PER_MHZ; /* 125 MHz */
break;
default:
netdev_err(port->ndev, "selected mode does not supported IET\n");
return -EOPNOTSUPP;
}
val /= MILLIHZ_PER_HZ; /* count per ms timeout */
val *= verify_time_ms; /* count for timeout ms */
@@ -295,20 +317,21 @@ static int am65_cpsw_iet_verify_wait(struct am65_cpsw_port *port)
u32 ctrl, status;
int try;
try = 20;
try = 3;
/* Reset the verify state machine by writing 1
* to LINKFAIL
*/
ctrl = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
ctrl |= AM65_CPSW_PN_IET_MAC_LINKFAIL;
writel(ctrl, port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
/* Clear MAC_LINKFAIL bit to start Verify. */
ctrl = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
ctrl &= ~AM65_CPSW_PN_IET_MAC_LINKFAIL;
writel(ctrl, port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
do {
/* Reset the verify state machine by writing 1
* to LINKFAIL
*/
ctrl = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
ctrl |= AM65_CPSW_PN_IET_MAC_LINKFAIL;
writel(ctrl, port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
/* Clear MAC_LINKFAIL bit to start Verify. */
ctrl = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
ctrl &= ~AM65_CPSW_PN_IET_MAC_LINKFAIL;
writel(ctrl, port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
msleep(port->qos.iet.verify_time_ms);
status = readl(port->port_base + AM65_CPSW_PN_REG_IET_STATUS);
@@ -330,7 +353,7 @@ static int am65_cpsw_iet_verify_wait(struct am65_cpsw_port *port)
netdev_dbg(port->ndev, "MAC Merge verify error\n");
return -ENODEV;
}
} while (try-- > 0);
} while (--try > 0);
netdev_dbg(port->ndev, "MAC Merge verify timeout\n");
return -ETIMEDOUT;

View File

@@ -73,8 +73,11 @@ int mdiobus_register_device(struct mdio_device *mdiodev)
return err;
err = mdiobus_register_reset(mdiodev);
if (err)
if (err) {
gpiod_put(mdiodev->reset_gpio);
mdiodev->reset_gpio = NULL;
return err;
}
/* Assert the reset signal */
mdio_device_reset(mdiodev, 1);

View File

@@ -4380,12 +4380,6 @@ static int lan8814_config_init(struct phy_device *phydev)
{
struct kszphy_priv *lan8814 = phydev->priv;
/* Reset the PHY */
lanphy_modify_page_reg(phydev, LAN8814_PAGE_COMMON_REGS,
LAN8814_QSGMII_SOFT_RESET,
LAN8814_QSGMII_SOFT_RESET_BIT,
LAN8814_QSGMII_SOFT_RESET_BIT);
/* Disable ANEG with QSGMII PCS Host side */
lanphy_modify_page_reg(phydev, LAN8814_PAGE_PORT_REGS,
LAN8814_QSGMII_PCS1G_ANEG_CONFIG,
@@ -4471,6 +4465,12 @@ static int lan8814_probe(struct phy_device *phydev)
addr, sizeof(struct lan8814_shared_priv));
if (phy_package_init_once(phydev)) {
/* Reset the PHY */
lanphy_modify_page_reg(phydev, LAN8814_PAGE_COMMON_REGS,
LAN8814_QSGMII_SOFT_RESET,
LAN8814_QSGMII_SOFT_RESET_BIT,
LAN8814_QSGMII_SOFT_RESET_BIT);
err = lan8814_release_coma_mode(phydev);
if (err)
return err;

View File

@@ -2631,22 +2631,28 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
return;
}
/* 1. Save the flags early, as the XDP program might overwrite them.
/* About the flags below:
* 1. Save the flags early, as the XDP program might overwrite them.
* These flags ensure packets marked as VIRTIO_NET_HDR_F_DATA_VALID
* stay valid after XDP processing.
* 2. XDP doesn't work with partially checksummed packets (refer to
* virtnet_xdp_set()), so packets marked as
* VIRTIO_NET_HDR_F_NEEDS_CSUM get dropped during XDP processing.
*/
flags = ((struct virtio_net_common_hdr *)buf)->hdr.flags;
if (vi->mergeable_rx_bufs)
if (vi->mergeable_rx_bufs) {
flags = ((struct virtio_net_common_hdr *)buf)->hdr.flags;
skb = receive_mergeable(dev, vi, rq, buf, ctx, len, xdp_xmit,
stats);
else if (vi->big_packets)
} else if (vi->big_packets) {
void *p = page_address((struct page *)buf);
flags = ((struct virtio_net_common_hdr *)p)->hdr.flags;
skb = receive_big(dev, vi, rq, buf, len, stats);
else
} else {
flags = ((struct virtio_net_common_hdr *)buf)->hdr.flags;
skb = receive_small(dev, vi, rq, buf, ctx, len, xdp_xmit, stats);
}
if (unlikely(!skb))
return;

View File

@@ -5961,6 +5961,9 @@ static int wmi_process_mgmt_tx_comp(struct ath11k *ar,
dma_unmap_single(ar->ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
info = IEEE80211_SKB_CB(msdu);
memset(&info->status, 0, sizeof(info->status));
info->status.rates[0].idx = -1;
if ((!(info->flags & IEEE80211_TX_CTL_NO_ACK)) &&
!tx_compl_param->status) {
info->flags |= IEEE80211_TX_STAT_ACK;

View File

@@ -708,18 +708,13 @@ static int
iwl_mld_get_chan_load_from_element(struct iwl_mld *mld,
struct ieee80211_bss_conf *link_conf)
{
struct ieee80211_vif *vif = link_conf->vif;
const struct cfg80211_bss_ies *ies;
const struct element *bss_load_elem = NULL;
const struct ieee80211_bss_load_elem *bss_load;
guard(rcu)();
if (ieee80211_vif_link_active(vif, link_conf->link_id))
ies = rcu_dereference(link_conf->bss->beacon_ies);
else
ies = rcu_dereference(link_conf->bss->ies);
ies = rcu_dereference(link_conf->bss->beacon_ies);
if (ies)
bss_load_elem = cfg80211_find_elem(WLAN_EID_QBSS_LOAD,
ies->data, ies->len);

View File

@@ -938,19 +938,12 @@ u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct iwl_mvm *mvm,
u16 iwl_mvm_mac_ctxt_get_beacon_flags(const struct iwl_fw *fw, u8 rate_idx)
{
u16 flags = iwl_mvm_mac80211_idx_to_hwrate(fw, rate_idx);
bool is_new_rate = iwl_fw_lookup_cmd_ver(fw, BEACON_TEMPLATE_CMD, 0) > 10;
u16 flags, cck_flag;
if (is_new_rate) {
flags = iwl_mvm_mac80211_idx_to_hwrate(fw, rate_idx);
cck_flag = IWL_MAC_BEACON_CCK;
} else {
cck_flag = IWL_MAC_BEACON_CCK_V1;
flags = iwl_fw_rate_idx_to_plcp(rate_idx);
}
if (rate_idx <= IWL_LAST_CCK_RATE)
flags |= cck_flag;
flags |= is_new_rate ? IWL_MAC_BEACON_CCK
: IWL_MAC_BEACON_CCK_V1;
return flags;
}

View File

@@ -463,7 +463,7 @@ static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm,
if (!aux_roc_te) /* Not a Aux ROC time event */
return -EINVAL;
iwl_mvm_te_check_trigger(mvm, notif, te_data);
iwl_mvm_te_check_trigger(mvm, notif, aux_roc_te);
IWL_DEBUG_TE(mvm,
"Aux ROC time event notification - UID = 0x%x action %d (error = %d)\n",
@@ -475,14 +475,14 @@ static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm,
/* End TE, notify mac80211 */
ieee80211_remain_on_channel_expired(mvm->hw);
iwl_mvm_roc_finished(mvm); /* flush aux queue */
list_del(&te_data->list); /* remove from list */
te_data->running = false;
te_data->vif = NULL;
te_data->uid = 0;
te_data->id = TE_MAX;
list_del(&aux_roc_te->list); /* remove from list */
aux_roc_te->running = false;
aux_roc_te->vif = NULL;
aux_roc_te->uid = 0;
aux_roc_te->id = TE_MAX;
} else if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_START) {
set_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status);
te_data->running = true;
aux_roc_te->running = true;
ieee80211_ready_on_channel(mvm->hw); /* Start TE */
} else {
IWL_DEBUG_TE(mvm,

View File

@@ -159,9 +159,15 @@ int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags,
u8 iwl_mvm_mac80211_idx_to_hwrate(const struct iwl_fw *fw, int rate_idx)
{
return (rate_idx >= IWL_FIRST_OFDM_RATE ?
rate_idx - IWL_FIRST_OFDM_RATE :
rate_idx);
if (iwl_fw_lookup_cmd_ver(fw, TX_CMD, 0) > 8)
/* In the new rate legacy rates are indexed:
* 0 - 3 for CCK and 0 - 7 for OFDM.
*/
return (rate_idx >= IWL_FIRST_OFDM_RATE ?
rate_idx - IWL_FIRST_OFDM_RATE :
rate_idx);
return iwl_fw_rate_idx_to_plcp(rate_idx);
}
u8 iwl_mvm_mac80211_ac_to_ucode_ac(enum ieee80211_ac_numbers ac)

View File

@@ -2966,6 +2966,51 @@ mwl8k_cmd_rf_antenna(struct ieee80211_hw *hw, int antenna, int mask)
/*
* CMD_SET_BEACON.
*/
static bool mwl8k_beacon_has_ds_params(const u8 *buf, int len)
{
const struct ieee80211_mgmt *mgmt = (const void *)buf;
int ies_len;
if (len <= offsetof(struct ieee80211_mgmt, u.beacon.variable))
return false;
ies_len = len - offsetof(struct ieee80211_mgmt, u.beacon.variable);
return cfg80211_find_ie(WLAN_EID_DS_PARAMS, mgmt->u.beacon.variable,
ies_len) != NULL;
}
static void mwl8k_beacon_copy_inject_ds_params(struct ieee80211_hw *hw,
u8 *buf_dst, const u8 *buf_src,
int src_len)
{
const struct ieee80211_mgmt *mgmt = (const void *)buf_src;
static const u8 before_ds_params[] = {
WLAN_EID_SSID,
WLAN_EID_SUPP_RATES,
};
const u8 *ies;
int hdr_len, left, offs, pos;
ies = mgmt->u.beacon.variable;
hdr_len = offsetof(struct ieee80211_mgmt, u.beacon.variable);
offs = ieee80211_ie_split(ies, src_len - hdr_len, before_ds_params,
ARRAY_SIZE(before_ds_params), 0);
pos = hdr_len + offs;
left = src_len - pos;
memcpy(buf_dst, buf_src, pos);
/* Inject a DSSS Parameter Set after SSID + Supp Rates */
buf_dst[pos + 0] = WLAN_EID_DS_PARAMS;
buf_dst[pos + 1] = 1;
buf_dst[pos + 2] = hw->conf.chandef.chan->hw_value;
memcpy(buf_dst + pos + 3, buf_src + pos, left);
}
struct mwl8k_cmd_set_beacon {
struct mwl8k_cmd_pkt_hdr header;
__le16 beacon_len;
@@ -2975,17 +3020,33 @@ struct mwl8k_cmd_set_beacon {
static int mwl8k_cmd_set_beacon(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u8 *beacon, int len)
{
bool ds_params_present = mwl8k_beacon_has_ds_params(beacon, len);
struct mwl8k_cmd_set_beacon *cmd;
int rc;
int rc, final_len = len;
cmd = kzalloc(sizeof(*cmd) + len, GFP_KERNEL);
if (!ds_params_present) {
/*
* mwl8k firmware requires a DS Params IE with the current
* channel in AP beacons. If mac80211/hostapd does not
* include it, inject one here. IE ID + length + channel
* number = 3 bytes.
*/
final_len += 3;
}
cmd = kzalloc(sizeof(*cmd) + final_len, GFP_KERNEL);
if (cmd == NULL)
return -ENOMEM;
cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_BEACON);
cmd->header.length = cpu_to_le16(sizeof(*cmd) + len);
cmd->beacon_len = cpu_to_le16(len);
memcpy(cmd->beacon, beacon, len);
cmd->header.length = cpu_to_le16(sizeof(*cmd) + final_len);
cmd->beacon_len = cpu_to_le16(final_len);
if (ds_params_present)
memcpy(cmd->beacon, beacon, len);
else
mwl8k_beacon_copy_inject_ds_params(hw, cmd->beacon, beacon,
len);
rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header);
kfree(cmd);

View File

@@ -2003,8 +2003,14 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
struct ieee80211_sta *sta = control->sta;
struct ieee80211_bss_conf *bss_conf;
/* This can happen in case of monitor injection */
if (!vif) {
ieee80211_free_txskb(hw, skb);
return;
}
if (link != IEEE80211_LINK_UNSPECIFIED) {
bss_conf = rcu_dereference(txi->control.vif->link_conf[link]);
bss_conf = rcu_dereference(vif->link_conf[link]);
if (sta)
link_sta = rcu_dereference(sta->link[link]);
} else {
@@ -2065,13 +2071,13 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
return;
}
if (txi->control.vif)
hwsim_check_magic(txi->control.vif);
if (vif)
hwsim_check_magic(vif);
if (control->sta)
hwsim_check_sta_magic(control->sta);
if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE))
ieee80211_get_tx_rates(txi->control.vif, control->sta, skb,
ieee80211_get_tx_rates(vif, control->sta, skb,
txi->control.rates,
ARRAY_SIZE(txi->control.rates));

View File

@@ -573,6 +573,8 @@ static int cq_create(struct mlx5_vdpa_net *ndev, u16 idx, u32 num_ent)
vcq->mcq.set_ci_db = vcq->db.db;
vcq->mcq.arm_db = vcq->db.db + 1;
vcq->mcq.cqe_sz = 64;
vcq->mcq.comp = mlx5_vdpa_cq_comp;
vcq->cqe = num_ent;
err = cq_frag_buf_alloc(ndev, &vcq->buf, num_ent);
if (err)
@@ -612,10 +614,6 @@ static int cq_create(struct mlx5_vdpa_net *ndev, u16 idx, u32 num_ent)
if (err)
goto err_vec;
vcq->mcq.comp = mlx5_vdpa_cq_comp;
vcq->cqe = num_ent;
vcq->mcq.set_ci_db = vcq->db.db;
vcq->mcq.arm_db = vcq->db.db + 1;
mlx5_cq_arm(&mvq->cq.mcq, MLX5_CQ_DB_REQ_NOT, uar_page, mvq->cq.mcq.cons_index);
kfree(in);
return 0;

View File

@@ -492,7 +492,7 @@ struct ethtool_pause_stats {
};
#define ETHTOOL_MAX_LANES 8
/**
/*
* IEEE 802.3ck/df defines 16 bins for FEC histogram plus one more for
* the end-of-list marker, total 17 items
*/

View File

@@ -183,6 +183,7 @@ static inline void mlx5_cq_put(struct mlx5_core_cq *cq)
complete(&cq->free);
}
void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq, struct mlx5_eqe *eqe);
int mlx5_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
u32 *in, int inlen, u32 *out, int outlen);
int mlx5_core_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,

View File

@@ -2783,6 +2783,11 @@ struct hci_ev_le_per_adv_report {
__u8 data[];
} __packed;
#define HCI_EV_LE_PA_SYNC_LOST 0x10
struct hci_ev_le_pa_sync_lost {
__le16 handle;
} __packed;
#define LE_PA_DATA_COMPLETE 0x00
#define LE_PA_DATA_MORE_TO_COME 0x01
#define LE_PA_DATA_TRUNCATED 0x02

View File

@@ -53,6 +53,11 @@ static bool enable_6lowpan;
static struct l2cap_chan *listen_chan;
static DEFINE_MUTEX(set_lock);
enum {
LOWPAN_PEER_CLOSING,
LOWPAN_PEER_MAXBITS
};
struct lowpan_peer {
struct list_head list;
struct rcu_head rcu;
@@ -61,6 +66,8 @@ struct lowpan_peer {
/* peer addresses in various formats */
unsigned char lladdr[ETH_ALEN];
struct in6_addr peer_addr;
DECLARE_BITMAP(flags, LOWPAN_PEER_MAXBITS);
};
struct lowpan_btle_dev {
@@ -289,6 +296,7 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
local_skb->pkt_type = PACKET_HOST;
local_skb->dev = dev;
skb_reset_mac_header(local_skb);
skb_set_transport_header(local_skb, sizeof(struct ipv6hdr));
if (give_skb_to_upper(local_skb, dev) != NET_RX_SUCCESS) {
@@ -919,7 +927,9 @@ static int bt_6lowpan_disconnect(struct l2cap_conn *conn, u8 dst_type)
BT_DBG("peer %p chan %p", peer, peer->chan);
l2cap_chan_lock(peer->chan);
l2cap_chan_close(peer->chan, ENOENT);
l2cap_chan_unlock(peer->chan);
return 0;
}
@@ -956,10 +966,11 @@ static struct l2cap_chan *bt_6lowpan_listen(void)
}
static int get_l2cap_conn(char *buf, bdaddr_t *addr, u8 *addr_type,
struct l2cap_conn **conn)
struct l2cap_conn **conn, bool disconnect)
{
struct hci_conn *hcon;
struct hci_dev *hdev;
int le_addr_type;
int n;
n = sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu",
@@ -970,13 +981,32 @@ static int get_l2cap_conn(char *buf, bdaddr_t *addr, u8 *addr_type,
if (n < 7)
return -EINVAL;
if (disconnect) {
/* The "disconnect" debugfs command has used different address
* type constants than "connect" since 2015. Let's retain that
* for now even though it's obviously buggy...
*/
*addr_type += 1;
}
switch (*addr_type) {
case BDADDR_LE_PUBLIC:
le_addr_type = ADDR_LE_DEV_PUBLIC;
break;
case BDADDR_LE_RANDOM:
le_addr_type = ADDR_LE_DEV_RANDOM;
break;
default:
return -EINVAL;
}
/* The LE_PUBLIC address type is ignored because of BDADDR_ANY */
hdev = hci_get_route(addr, BDADDR_ANY, BDADDR_LE_PUBLIC);
if (!hdev)
return -ENOENT;
hci_dev_lock(hdev);
hcon = hci_conn_hash_lookup_le(hdev, addr, *addr_type);
hcon = hci_conn_hash_lookup_le(hdev, addr, le_addr_type);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
@@ -993,41 +1023,52 @@ static int get_l2cap_conn(char *buf, bdaddr_t *addr, u8 *addr_type,
static void disconnect_all_peers(void)
{
struct lowpan_btle_dev *entry;
struct lowpan_peer *peer, *tmp_peer, *new_peer;
struct list_head peers;
struct lowpan_peer *peer;
int nchans;
INIT_LIST_HEAD(&peers);
/* We make a separate list of peers as the close_cb() will
* modify the device peers list so it is better not to mess
* with the same list at the same time.
/* l2cap_chan_close() cannot be called from RCU, and lock ordering
* chan->lock > devices_lock prevents taking write side lock, so copy
* then close.
*/
rcu_read_lock();
list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
list_for_each_entry_rcu(peer, &entry->peers, list) {
new_peer = kmalloc(sizeof(*new_peer), GFP_ATOMIC);
if (!new_peer)
break;
new_peer->chan = peer->chan;
INIT_LIST_HEAD(&new_peer->list);
list_add(&new_peer->list, &peers);
}
}
list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list)
list_for_each_entry_rcu(peer, &entry->peers, list)
clear_bit(LOWPAN_PEER_CLOSING, peer->flags);
rcu_read_unlock();
spin_lock(&devices_lock);
list_for_each_entry_safe(peer, tmp_peer, &peers, list) {
l2cap_chan_close(peer->chan, ENOENT);
do {
struct l2cap_chan *chans[32];
int i;
list_del_rcu(&peer->list);
kfree_rcu(peer, rcu);
}
spin_unlock(&devices_lock);
nchans = 0;
spin_lock(&devices_lock);
list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
list_for_each_entry_rcu(peer, &entry->peers, list) {
if (test_and_set_bit(LOWPAN_PEER_CLOSING,
peer->flags))
continue;
l2cap_chan_hold(peer->chan);
chans[nchans++] = peer->chan;
if (nchans >= ARRAY_SIZE(chans))
goto done;
}
}
done:
spin_unlock(&devices_lock);
for (i = 0; i < nchans; ++i) {
l2cap_chan_lock(chans[i]);
l2cap_chan_close(chans[i], ENOENT);
l2cap_chan_unlock(chans[i]);
l2cap_chan_put(chans[i]);
}
} while (nchans);
}
struct set_enable {
@@ -1050,7 +1091,9 @@ static void do_enable_set(struct work_struct *work)
mutex_lock(&set_lock);
if (listen_chan) {
l2cap_chan_lock(listen_chan);
l2cap_chan_close(listen_chan, 0);
l2cap_chan_unlock(listen_chan);
l2cap_chan_put(listen_chan);
}
@@ -1103,13 +1146,15 @@ static ssize_t lowpan_control_write(struct file *fp,
buf[buf_size] = '\0';
if (memcmp(buf, "connect ", 8) == 0) {
ret = get_l2cap_conn(&buf[8], &addr, &addr_type, &conn);
ret = get_l2cap_conn(&buf[8], &addr, &addr_type, &conn, false);
if (ret == -EINVAL)
return ret;
mutex_lock(&set_lock);
if (listen_chan) {
l2cap_chan_lock(listen_chan);
l2cap_chan_close(listen_chan, 0);
l2cap_chan_unlock(listen_chan);
l2cap_chan_put(listen_chan);
listen_chan = NULL;
}
@@ -1140,7 +1185,7 @@ static ssize_t lowpan_control_write(struct file *fp,
}
if (memcmp(buf, "disconnect ", 11) == 0) {
ret = get_l2cap_conn(&buf[11], &addr, &addr_type, &conn);
ret = get_l2cap_conn(&buf[11], &addr, &addr_type, &conn, true);
if (ret < 0)
return ret;
@@ -1271,7 +1316,9 @@ static void __exit bt_6lowpan_exit(void)
debugfs_remove(lowpan_control_debugfs);
if (listen_chan) {
l2cap_chan_lock(listen_chan);
l2cap_chan_close(listen_chan, 0);
l2cap_chan_unlock(listen_chan);
l2cap_chan_put(listen_chan);
}

View File

@@ -769,21 +769,23 @@ static void find_bis(struct hci_conn *conn, void *data)
d->count++;
}
static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, struct hci_conn *conn)
static int hci_le_big_terminate(struct hci_dev *hdev, struct hci_conn *conn)
{
struct iso_list_data *d;
int ret;
bt_dev_dbg(hdev, "big 0x%2.2x sync_handle 0x%4.4x", big, conn->sync_handle);
bt_dev_dbg(hdev, "hcon %p big 0x%2.2x sync_handle 0x%4.4x", conn,
conn->iso_qos.bcast.big, conn->sync_handle);
d = kzalloc(sizeof(*d), GFP_KERNEL);
if (!d)
return -ENOMEM;
d->big = big;
d->big = conn->iso_qos.bcast.big;
d->sync_handle = conn->sync_handle;
if (test_and_clear_bit(HCI_CONN_PA_SYNC, &conn->flags)) {
if (conn->type == PA_LINK &&
test_and_clear_bit(HCI_CONN_PA_SYNC, &conn->flags)) {
hci_conn_hash_list_flag(hdev, find_bis, PA_LINK,
HCI_CONN_PA_SYNC, d);
@@ -801,6 +803,9 @@ static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, struct hci_conn *c
d->big_sync_term = true;
}
if (!d->pa_sync_term && !d->big_sync_term)
return 0;
ret = hci_cmd_sync_queue(hdev, big_terminate_sync, d,
terminate_big_destroy);
if (ret)
@@ -852,8 +857,7 @@ static void bis_cleanup(struct hci_conn *conn)
hci_le_terminate_big(hdev, conn);
} else {
hci_le_big_terminate(hdev, conn->iso_qos.bcast.big,
conn);
hci_le_big_terminate(hdev, conn);
}
}
@@ -994,19 +998,20 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t
conn->mtu = hdev->le_mtu ? hdev->le_mtu : hdev->acl_mtu;
break;
case CIS_LINK:
case BIS_LINK:
case PA_LINK:
/* conn->src should reflect the local identity address */
hci_copy_identity_address(hdev, &conn->src, &conn->src_type);
/* set proper cleanup function */
if (!bacmp(dst, BDADDR_ANY))
conn->cleanup = bis_cleanup;
else if (conn->role == HCI_ROLE_MASTER)
if (conn->role == HCI_ROLE_MASTER)
conn->cleanup = cis_cleanup;
conn->mtu = hdev->iso_mtu ? hdev->iso_mtu :
hdev->le_mtu ? hdev->le_mtu : hdev->acl_mtu;
conn->mtu = hdev->iso_mtu;
break;
case PA_LINK:
case BIS_LINK:
/* conn->src should reflect the local identity address */
hci_copy_identity_address(hdev, &conn->src, &conn->src_type);
conn->cleanup = bis_cleanup;
conn->mtu = hdev->iso_mtu;
break;
case SCO_LINK:
if (lmp_esco_capable(hdev))

View File

@@ -5843,6 +5843,29 @@ static void hci_le_enh_conn_complete_evt(struct hci_dev *hdev, void *data,
le16_to_cpu(ev->supervision_timeout));
}
static void hci_le_pa_sync_lost_evt(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
struct hci_ev_le_pa_sync_lost *ev = data;
u16 handle = le16_to_cpu(ev->handle);
struct hci_conn *conn;
bt_dev_dbg(hdev, "sync handle 0x%4.4x", handle);
hci_dev_lock(hdev);
/* Delete the pa sync connection */
conn = hci_conn_hash_lookup_pa_sync_handle(hdev, handle);
if (conn) {
clear_bit(HCI_CONN_BIG_SYNC, &conn->flags);
clear_bit(HCI_CONN_PA_SYNC, &conn->flags);
hci_disconn_cfm(conn, HCI_ERROR_REMOTE_USER_TERM);
hci_conn_del(conn);
}
hci_dev_unlock(hdev);
}
static void hci_le_ext_adv_term_evt(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
@@ -7001,14 +7024,9 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
continue;
}
if (ev->status != 0x42) {
if (ev->status != 0x42)
/* Mark PA sync as established */
set_bit(HCI_CONN_PA_SYNC, &bis->flags);
/* Reset cleanup callback of PA Sync so it doesn't
* terminate the sync when deleting the connection.
*/
conn->cleanup = NULL;
}
bis->sync_handle = conn->sync_handle;
bis->iso_qos.bcast.big = ev->handle;
@@ -7051,29 +7069,24 @@ static void hci_le_big_sync_lost_evt(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
struct hci_evt_le_big_sync_lost *ev = data;
struct hci_conn *bis, *conn;
bool mgmt_conn;
struct hci_conn *bis;
bool mgmt_conn = false;
bt_dev_dbg(hdev, "big handle 0x%2.2x", ev->handle);
hci_dev_lock(hdev);
/* Delete the pa sync connection */
bis = hci_conn_hash_lookup_pa_sync_big_handle(hdev, ev->handle);
if (bis) {
conn = hci_conn_hash_lookup_pa_sync_handle(hdev,
bis->sync_handle);
if (conn)
hci_conn_del(conn);
}
/* Delete each bis connection */
while ((bis = hci_conn_hash_lookup_big_state(hdev, ev->handle,
BT_CONNECTED,
HCI_ROLE_SLAVE))) {
mgmt_conn = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &bis->flags);
mgmt_device_disconnected(hdev, &bis->dst, bis->type, bis->dst_type,
ev->reason, mgmt_conn);
if (!mgmt_conn) {
mgmt_conn = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED,
&bis->flags);
mgmt_device_disconnected(hdev, &bis->dst, bis->type,
bis->dst_type, ev->reason,
mgmt_conn);
}
clear_bit(HCI_CONN_BIG_SYNC, &bis->flags);
hci_disconn_cfm(bis, ev->reason);
@@ -7187,6 +7200,9 @@ static const struct hci_le_ev {
hci_le_per_adv_report_evt,
sizeof(struct hci_ev_le_per_adv_report),
HCI_MAX_EVENT_SIZE),
/* [0x10 = HCI_EV_LE_PA_SYNC_LOST] */
HCI_LE_EV(HCI_EV_LE_PA_SYNC_LOST, hci_le_pa_sync_lost_evt,
sizeof(struct hci_ev_le_pa_sync_lost)),
/* [0x12 = HCI_EV_LE_EXT_ADV_SET_TERM] */
HCI_LE_EV(HCI_EV_LE_EXT_ADV_SET_TERM, hci_le_ext_adv_term_evt,
sizeof(struct hci_evt_le_ext_adv_set_term)),

View File

@@ -6999,7 +6999,7 @@ static void create_pa_complete(struct hci_dev *hdev, void *data, int err)
hci_dev_lock(hdev);
if (!hci_conn_valid(hdev, conn))
if (hci_conn_valid(hdev, conn))
clear_bit(HCI_CONN_CREATE_PA_SYNC, &conn->flags);
if (!err)

View File

@@ -497,6 +497,7 @@ void l2cap_chan_hold(struct l2cap_chan *c)
kref_get(&c->kref);
}
EXPORT_SYMBOL_GPL(l2cap_chan_hold);
struct l2cap_chan *l2cap_chan_hold_unless_zero(struct l2cap_chan *c)
{

View File

@@ -9497,6 +9497,7 @@ void mgmt_index_removed(struct hci_dev *hdev)
cancel_delayed_work_sync(&hdev->discov_off);
cancel_delayed_work_sync(&hdev->service_cache);
cancel_delayed_work_sync(&hdev->rpa_expired);
cancel_delayed_work_sync(&hdev->mesh_send_done);
}
void mgmt_power_on(struct hci_dev *hdev, int err)

View File

@@ -811,6 +811,10 @@ static void __netpoll_cleanup(struct netpoll *np)
if (!npinfo)
return;
/* At this point, there is a single npinfo instance per netdevice, and
* its refcnt tracks how many netpoll structures are linked to it. We
* only perform npinfo cleanup when the refcnt decrements to zero.
*/
if (refcount_dec_and_test(&npinfo->refcnt)) {
const struct net_device_ops *ops;
@@ -820,8 +824,7 @@ static void __netpoll_cleanup(struct netpoll *np)
RCU_INIT_POINTER(np->dev->npinfo, NULL);
call_rcu(&npinfo->rcu, rcu_cleanup_netpoll_info);
} else
RCU_INIT_POINTER(np->dev->npinfo, NULL);
}
skb_pool_flush(np);
}

View File

@@ -176,7 +176,8 @@ static struct sk_buff *brcm_tag_rcv_ll(struct sk_buff *skb,
/* Remove Broadcom tag and update checksum */
skb_pull_rcsum(skb, BRCM_TAG_LEN);
dsa_default_offload_fwd_mark(skb);
if (likely(!is_link_local_ether_addr(eth_hdr(skb)->h_dest)))
dsa_default_offload_fwd_mark(skb);
return skb;
}
@@ -250,7 +251,8 @@ static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb,
/* Remove Broadcom tag and update checksum */
skb_pull_rcsum(skb, len);
dsa_default_offload_fwd_mark(skb);
if (likely(!is_link_local_ether_addr(eth_hdr(skb)->h_dest)))
dsa_default_offload_fwd_mark(skb);
dsa_strip_etype_header(skb, len);

View File

@@ -259,6 +259,7 @@ static int tls_handshake_accept(struct handshake_req *req,
out_cancel:
genlmsg_cancel(msg, hdr);
nlmsg_free(msg);
out:
return ret;
}

View File

@@ -320,6 +320,9 @@ static void send_hsr_supervision_frame(struct hsr_port *port,
}
hsr_stag = skb_put(skb, sizeof(struct hsr_sup_tag));
skb_set_network_header(skb, ETH_HLEN + HSR_HLEN);
skb_reset_mac_len(skb);
set_hsr_stag_path(hsr_stag, (hsr->prot_version ? 0x0 : 0xf));
set_hsr_stag_HSR_ver(hsr_stag, hsr->prot_version);
@@ -334,7 +337,7 @@ static void send_hsr_supervision_frame(struct hsr_port *port,
}
hsr_stag->tlv.HSR_TLV_type = type;
/* TODO: Why 12 in HSRv0? */
/* HSRv0 has 6 unused bytes after the MAC */
hsr_stag->tlv.HSR_TLV_length = hsr->prot_version ?
sizeof(struct hsr_sup_payload) : 12;

View File

@@ -262,15 +262,23 @@ static struct sk_buff *prp_fill_rct(struct sk_buff *skb,
return skb;
}
static void hsr_set_path_id(struct hsr_ethhdr *hsr_ethhdr,
static void hsr_set_path_id(struct hsr_frame_info *frame,
struct hsr_ethhdr *hsr_ethhdr,
struct hsr_port *port)
{
int path_id;
if (port->type == HSR_PT_SLAVE_A)
path_id = 0;
else
path_id = 1;
if (port->hsr->prot_version) {
if (port->type == HSR_PT_SLAVE_A)
path_id = 0;
else
path_id = 1;
} else {
if (frame->is_supervision)
path_id = 0xf;
else
path_id = 1;
}
set_hsr_tag_path(&hsr_ethhdr->hsr_tag, path_id);
}
@@ -304,7 +312,7 @@ static struct sk_buff *hsr_fill_tag(struct sk_buff *skb,
else
hsr_ethhdr = (struct hsr_ethhdr *)pc;
hsr_set_path_id(hsr_ethhdr, port);
hsr_set_path_id(frame, hsr_ethhdr, port);
set_hsr_tag_LSDU_size(&hsr_ethhdr->hsr_tag, lsdu_size);
hsr_ethhdr->hsr_tag.sequence_nr = htons(frame->sequence_nr);
hsr_ethhdr->hsr_tag.encap_proto = hsr_ethhdr->ethhdr.h_proto;
@@ -330,7 +338,7 @@ struct sk_buff *hsr_create_tagged_frame(struct hsr_frame_info *frame,
(struct hsr_ethhdr *)skb_mac_header(frame->skb_hsr);
/* set the lane id properly */
hsr_set_path_id(hsr_ethhdr, port);
hsr_set_path_id(frame, hsr_ethhdr, port);
return skb_clone(frame->skb_hsr, GFP_ATOMIC);
} else if (port->dev->features & NETIF_F_HW_HSR_TAG_INS) {
return skb_clone(frame->skb_std, GFP_ATOMIC);

View File

@@ -607,6 +607,11 @@ static void fnhe_remove_oldest(struct fnhe_hash_bucket *hash)
oldest_p = fnhe_p;
}
}
/* Clear oldest->fnhe_daddr to prevent this fnhe from being
* rebound with new dsts in rt_bind_exception().
*/
oldest->fnhe_daddr = 0;
fnhe_flush_routes(oldest);
*oldest_p = oldest->fnhe_next;
kfree_rcu(oldest, rcu);

View File

@@ -223,6 +223,10 @@ static int ieee80211_can_powered_addr_change(struct ieee80211_sub_if_data *sdata
if (netif_carrier_ok(sdata->dev))
return -EBUSY;
/* if any stations are set known (so they know this vif too), reject */
if (sta_info_get_by_idx(sdata, 0))
return -EBUSY;
/* First check no ROC work is happening on this iface */
list_for_each_entry(roc, &local->roc_list, list) {
if (roc->sdata != sdata)
@@ -242,12 +246,16 @@ static int ieee80211_can_powered_addr_change(struct ieee80211_sub_if_data *sdata
ret = -EBUSY;
}
/*
* More interface types could be added here but changing the
* address while powered makes the most sense in client modes.
*/
switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT:
/* More interface types could be added here but changing the
* address while powered makes the most sense in client modes.
*/
/* refuse while connecting */
if (sdata->u.mgd.auth_data || sdata->u.mgd.assoc_data)
return -EBUSY;
break;
default:
ret = -EOPNOTSUPP;

View File

@@ -5360,10 +5360,14 @@ void ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
if (WARN_ON(!local->started))
goto drop;
if (likely(!(status->flag & RX_FLAG_FAILED_PLCP_CRC))) {
if (likely(!(status->flag & RX_FLAG_FAILED_PLCP_CRC) &&
!(status->flag & RX_FLAG_NO_PSDU &&
status->zero_length_psdu_type ==
IEEE80211_RADIOTAP_ZERO_LEN_PSDU_NOT_CAPTURED))) {
/*
* Validate the rate, unless a PLCP error means that
* we probably can't have a valid rate here anyway.
* Validate the rate, unless there was a PLCP error which may
* have an invalid rate or the PSDU was not capture and may be
* missing rate information.
*/
switch (status->encoding) {

View File

@@ -195,13 +195,15 @@ static inline int tcf_connmark_dump(struct sk_buff *skb, struct tc_action *a,
const struct tcf_connmark_info *ci = to_connmark(a);
unsigned char *b = skb_tail_pointer(skb);
const struct tcf_connmark_parms *parms;
struct tc_connmark opt = {
.index = ci->tcf_index,
.refcnt = refcount_read(&ci->tcf_refcnt) - ref,
.bindcnt = atomic_read(&ci->tcf_bindcnt) - bind,
};
struct tc_connmark opt;
struct tcf_t t;
memset(&opt, 0, sizeof(opt));
opt.index = ci->tcf_index;
opt.refcnt = refcount_read(&ci->tcf_refcnt) - ref;
opt.bindcnt = atomic_read(&ci->tcf_bindcnt) - bind;
rcu_read_lock();
parms = rcu_dereference(ci->parms);

View File

@@ -644,13 +644,15 @@ static int tcf_ife_dump(struct sk_buff *skb, struct tc_action *a, int bind,
unsigned char *b = skb_tail_pointer(skb);
struct tcf_ife_info *ife = to_ife(a);
struct tcf_ife_params *p;
struct tc_ife opt = {
.index = ife->tcf_index,
.refcnt = refcount_read(&ife->tcf_refcnt) - ref,
.bindcnt = atomic_read(&ife->tcf_bindcnt) - bind,
};
struct tc_ife opt;
struct tcf_t t;
memset(&opt, 0, sizeof(opt));
opt.index = ife->tcf_index,
opt.refcnt = refcount_read(&ife->tcf_refcnt) - ref,
opt.bindcnt = atomic_read(&ife->tcf_bindcnt) - bind,
spin_lock_bh(&ife->tcf_lock);
opt.action = ife->tcf_action;
p = rcu_dereference_protected(ife->params,

View File

@@ -1599,6 +1599,11 @@ static int __tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n,
NL_SET_ERR_MSG(extack, "Failed to find specified qdisc");
return -ENOENT;
}
if (p->flags & TCQ_F_INGRESS) {
NL_SET_ERR_MSG(extack,
"Cannot add children to ingress/clsact qdisc");
return -EOPNOTSUPP;
}
q = qdisc_leaf(p, clid, extack);
if (IS_ERR(q))
return PTR_ERR(q);

View File

@@ -180,9 +180,10 @@ static inline void dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q)
static void try_bulk_dequeue_skb(struct Qdisc *q,
struct sk_buff *skb,
const struct netdev_queue *txq,
int *packets)
int *packets, int budget)
{
int bytelimit = qdisc_avail_bulklimit(txq) - skb->len;
int cnt = 0;
while (bytelimit > 0) {
struct sk_buff *nskb = q->dequeue(q);
@@ -193,8 +194,10 @@ static void try_bulk_dequeue_skb(struct Qdisc *q,
bytelimit -= nskb->len; /* covers GSO len */
skb->next = nskb;
skb = nskb;
(*packets)++; /* GSO counts as one pkt */
if (++cnt >= budget)
break;
}
(*packets) += cnt;
skb_mark_not_on_list(skb);
}
@@ -228,7 +231,7 @@ static void try_bulk_dequeue_skb_slow(struct Qdisc *q,
* A requeued skb (via q->gso_skb) can also be a SKB list.
*/
static struct sk_buff *dequeue_skb(struct Qdisc *q, bool *validate,
int *packets)
int *packets, int budget)
{
const struct netdev_queue *txq = q->dev_queue;
struct sk_buff *skb = NULL;
@@ -295,7 +298,7 @@ validate:
if (skb) {
bulk:
if (qdisc_may_bulk(q))
try_bulk_dequeue_skb(q, skb, txq, packets);
try_bulk_dequeue_skb(q, skb, txq, packets, budget);
else
try_bulk_dequeue_skb_slow(q, skb, packets);
}
@@ -387,7 +390,7 @@ bool sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
* >0 - queue is not empty.
*
*/
static inline bool qdisc_restart(struct Qdisc *q, int *packets)
static inline bool qdisc_restart(struct Qdisc *q, int *packets, int budget)
{
spinlock_t *root_lock = NULL;
struct netdev_queue *txq;
@@ -396,7 +399,7 @@ static inline bool qdisc_restart(struct Qdisc *q, int *packets)
bool validate;
/* Dequeue packet */
skb = dequeue_skb(q, &validate, packets);
skb = dequeue_skb(q, &validate, packets, budget);
if (unlikely(!skb))
return false;
@@ -414,7 +417,7 @@ void __qdisc_run(struct Qdisc *q)
int quota = READ_ONCE(net_hotdata.dev_tx_weight);
int packets;
while (qdisc_restart(q, &packets)) {
while (qdisc_restart(q, &packets, quota)) {
quota -= packets;
if (quota <= 0) {
if (q->flags & TCQ_F_NOLOCK)

View File

@@ -486,6 +486,7 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
if (tp->rttvar || tp->srtt) {
struct net *net = tp->asoc->base.net;
unsigned int rto_beta, rto_alpha;
/* 6.3.1 C3) When a new RTT measurement R' is made, set
* RTTVAR <- (1 - RTO.Beta) * RTTVAR + RTO.Beta * |SRTT - R'|
* SRTT <- (1 - RTO.Alpha) * SRTT + RTO.Alpha * R'
@@ -497,10 +498,14 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
* For example, assuming the default value of RTO.Alpha of
* 1/8, rto_alpha would be expressed as 3.
*/
tp->rttvar = tp->rttvar - (tp->rttvar >> net->sctp.rto_beta)
+ (((__u32)abs((__s64)tp->srtt - (__s64)rtt)) >> net->sctp.rto_beta);
tp->srtt = tp->srtt - (tp->srtt >> net->sctp.rto_alpha)
+ (rtt >> net->sctp.rto_alpha);
rto_beta = READ_ONCE(net->sctp.rto_beta);
if (rto_beta < 32)
tp->rttvar = tp->rttvar - (tp->rttvar >> rto_beta)
+ (((__u32)abs((__s64)tp->srtt - (__s64)rtt)) >> rto_beta);
rto_alpha = READ_ONCE(net->sctp.rto_alpha);
if (rto_alpha < 32)
tp->srtt = tp->srtt - (tp->srtt >> rto_alpha)
+ (rtt >> rto_alpha);
} else {
/* 6.3.1 C2) When the first RTT measurement R is made, set
* SRTT <- R, RTTVAR <- R/2.

View File

@@ -890,6 +890,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
return SMC_CLC_DECL_CNFERR;
}
pclc_base->hdr.typev1 = SMC_TYPE_N;
ini->smc_type_v1 = SMC_TYPE_N;
} else {
pclc_base->iparea_offset = htons(sizeof(*pclc_smcd));
plen += sizeof(*pclc_prfx) +

View File

@@ -238,7 +238,7 @@ static int __strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
strp_parser_err(strp, -EMSGSIZE, desc);
break;
} else if (len <= (ssize_t)head->len -
skb->len - stm->strp.offset) {
(ssize_t)skb->len - stm->strp.offset) {
/* Length must be into new skb (and also
* greater than zero)
*/

View File

@@ -145,7 +145,9 @@ void tipc_net_finalize_work(struct work_struct *work)
{
struct tipc_net *tn = container_of(work, struct tipc_net, work);
rtnl_lock();
tipc_net_finalize(tipc_link_net(tn->bcl), tn->trial_addr);
rtnl_unlock();
}
void tipc_net_stop(struct net *net)

View File

@@ -145,6 +145,7 @@ enum unix_vertex_index {
};
static unsigned long unix_vertex_unvisited_index = UNIX_VERTEX_INDEX_MARK1;
static unsigned long unix_vertex_max_scc_index = UNIX_VERTEX_INDEX_START;
static void unix_add_edge(struct scm_fp_list *fpl, struct unix_edge *edge)
{
@@ -153,6 +154,7 @@ static void unix_add_edge(struct scm_fp_list *fpl, struct unix_edge *edge)
if (!vertex) {
vertex = list_first_entry(&fpl->vertices, typeof(*vertex), entry);
vertex->index = unix_vertex_unvisited_index;
vertex->scc_index = ++unix_vertex_max_scc_index;
vertex->out_degree = 0;
INIT_LIST_HEAD(&vertex->edges);
INIT_LIST_HEAD(&vertex->scc_entry);
@@ -489,10 +491,15 @@ prev_vertex:
scc_dead = unix_vertex_dead(v);
}
if (scc_dead)
if (scc_dead) {
unix_collect_skb(&scc, hitlist);
else if (!unix_graph_maybe_cyclic)
unix_graph_maybe_cyclic = unix_scc_cyclic(&scc);
} else {
if (unix_vertex_max_scc_index < vertex->scc_index)
unix_vertex_max_scc_index = vertex->scc_index;
if (!unix_graph_maybe_cyclic)
unix_graph_maybe_cyclic = unix_scc_cyclic(&scc);
}
list_del(&scc);
}
@@ -507,6 +514,7 @@ static void unix_walk_scc(struct sk_buff_head *hitlist)
unsigned long last_index = UNIX_VERTEX_INDEX_START;
unix_graph_maybe_cyclic = false;
unix_vertex_max_scc_index = UNIX_VERTEX_INDEX_START;
/* Visit every vertex exactly once.
* __unix_walk_scc() moves visited vertices to unix_visited_vertices.

View File

@@ -861,6 +861,18 @@ class TypeIndexedArray(Type):
return [f"{member} = {self.c_name};",
f"{presence} = n_{self.c_name};"]
def free_needs_iter(self):
return self.sub_type == 'nest'
def _free_lines(self, ri, var, ref):
lines = []
if self.sub_type == 'nest':
lines += [
f"for (i = 0; i < {var}->{ref}_count.{self.c_name}; i++)",
f'{self.nested_render_name}_free(&{var}->{ref}{self.c_name}[i]);',
]
lines += f"free({var}->{ref}{self.c_name});",
return lines
class TypeNestTypeValue(Type):
def _complex_member_type(self, ri):

View File

@@ -18,6 +18,7 @@ TEST_PROGS := \
netcons_fragmented_msg.sh \
netcons_overflow.sh \
netcons_sysdata.sh \
netcons_torture.sh \
netpoll_basic.py \
ping.py \
psp.py \

View File

@@ -14,6 +14,7 @@ TEST_PROGS := \
dev_addr_lists.sh \
mode-1-recovery-updelay.sh \
mode-2-recovery-updelay.sh \
netcons_over_bonding.sh \
# end of TEST_PROGS
TEST_FILES := \
@@ -24,6 +25,7 @@ TEST_FILES := \
TEST_INCLUDES := \
../../../net/lib.sh \
../lib/sh/lib_netcons.sh \
../../../net/forwarding/lib.sh \
# end of TEST_INCLUDES

View File

@@ -1,5 +1,6 @@
CONFIG_BONDING=y
CONFIG_BRIDGE=y
CONFIG_CONFIGFS_FS=y
CONFIG_DUMMY=y
CONFIG_INET_ESP=y
CONFIG_INET_ESP_OFFLOAD=y
@@ -9,6 +10,9 @@ CONFIG_MACVLAN=y
CONFIG_NET_ACT_GACT=y
CONFIG_NET_CLS_FLOWER=y
CONFIG_NET_CLS_MATCHALL=m
CONFIG_NETCONSOLE=m
CONFIG_NETCONSOLE_DYNAMIC=y
CONFIG_NETCONSOLE_EXTENDED_LOG=y
CONFIG_NETDEVSIM=m
CONFIG_NET_SCH_INGRESS=y
CONFIG_NLMON=y

View File

@@ -0,0 +1,361 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: GPL-2.0
#
# This selftest exercises trying to have multiple netpoll users at the same
# time.
#
# This selftest has multiple smalls test inside, and the goal is to
# get interfaces with bonding and netconsole in different orders in order
# to catch any possible issue.
#
# The main test composes of four interfaces being created using netdevsim; two
# of them are bonded to serve as the netconsole's transmit interface. The
# remaining two interfaces are similarly bonded and assigned to a separate
# network namespace, which acts as the receive interface, where socat monitors
# for incoming messages.
#
# A netconsole message is then sent to ensure it is properly received across
# this configuration.
#
# Later, run a few other tests, to make sure that bonding and netconsole
# cannot coexist.
#
# The test's objective is to exercise netpoll usage when managed simultaneously
# by multiple subsystems (netconsole and bonding).
#
# Author: Breno Leitao <leitao@debian.org>
set -euo pipefail
SCRIPTDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")")
source "${SCRIPTDIR}"/../lib/sh/lib_netcons.sh
modprobe netdevsim 2> /dev/null || true
modprobe netconsole 2> /dev/null || true
modprobe bonding 2> /dev/null || true
modprobe veth 2> /dev/null || true
# The content of kmsg will be save to the following file
OUTPUT_FILE="/tmp/${TARGET}"
# Check for basic system dependency and exit if not found
check_for_dependencies
# Set current loglevel to KERN_INFO(6), and default to KERN_NOTICE(5)
echo "6 5" > /proc/sys/kernel/printk
# Remove the namespace, interfaces and netconsole target on exit
trap cleanup_bond EXIT
FORMAT="extended"
IP_VERSION="ipv4"
VETH0="veth"$(( RANDOM % 256))
VETH1="veth"$((256 + RANDOM % 256))
TXNS=""
RXNS=""
# Create "bond_tx_XX" and "bond_rx_XX" interfaces, and set DSTIF and SRCIF with
# the bonding interfaces
function setup_bonding_ifaces() {
local RAND=$(( RANDOM % 100 ))
BOND_TX_MAIN_IF="bond_tx_$RAND"
BOND_RX_MAIN_IF="bond_rx_$RAND"
# Setup TX
if ! ip -n "${TXNS}" link add "${BOND_TX_MAIN_IF}" type bond mode balance-rr
then
echo "Failed to create bond TX interface. Is CONFIG_BONDING set?" >&2
# only clean nsim ifaces and namespace. Nothing else has been
# initialized
cleanup_bond_nsim
trap - EXIT
exit "${ksft_skip}"
fi
# create_netdevsim() got the interface up, but it needs to be down
# before being enslaved.
ip -n "${TXNS}" \
link set "${BOND_TX1_SLAVE_IF}" down
ip -n "${TXNS}" \
link set "${BOND_TX2_SLAVE_IF}" down
ip -n "${TXNS}" \
link set "${BOND_TX1_SLAVE_IF}" master "${BOND_TX_MAIN_IF}"
ip -n "${TXNS}" \
link set "${BOND_TX2_SLAVE_IF}" master "${BOND_TX_MAIN_IF}"
ip -n "${TXNS}" \
link set "${BOND_TX_MAIN_IF}" up
# Setup RX
ip -n "${RXNS}" \
link add "${BOND_RX_MAIN_IF}" type bond mode balance-rr
ip -n "${RXNS}" \
link set "${BOND_RX1_SLAVE_IF}" down
ip -n "${RXNS}" \
link set "${BOND_RX2_SLAVE_IF}" down
ip -n "${RXNS}" \
link set "${BOND_RX1_SLAVE_IF}" master "${BOND_RX_MAIN_IF}"
ip -n "${RXNS}" \
link set "${BOND_RX2_SLAVE_IF}" master "${BOND_RX_MAIN_IF}"
ip -n "${RXNS}" \
link set "${BOND_RX_MAIN_IF}" up
export DSTIF="${BOND_RX_MAIN_IF}"
export SRCIF="${BOND_TX_MAIN_IF}"
}
# Create 4 netdevsim interfaces. Two of them will be bound to TX bonding iface
# and the other two will be bond to the RX interface (on the other namespace)
function create_ifaces_bond() {
BOND_TX1_SLAVE_IF=$(create_netdevsim "${NSIM_BOND_TX_1}" "${TXNS}")
BOND_TX2_SLAVE_IF=$(create_netdevsim "${NSIM_BOND_TX_2}" "${TXNS}")
BOND_RX1_SLAVE_IF=$(create_netdevsim "${NSIM_BOND_RX_1}" "${RXNS}")
BOND_RX2_SLAVE_IF=$(create_netdevsim "${NSIM_BOND_RX_2}" "${RXNS}")
}
# netdevsim link BOND_TX to BOND_RX interfaces
function link_ifaces_bond() {
local BOND_TX1_SLAVE_IFIDX
local BOND_TX2_SLAVE_IFIDX
local BOND_RX1_SLAVE_IFIDX
local BOND_RX2_SLAVE_IFIDX
local TXNS_FD
local RXNS_FD
BOND_TX1_SLAVE_IFIDX=$(ip netns exec "${TXNS}" \
cat /sys/class/net/"$BOND_TX1_SLAVE_IF"/ifindex)
BOND_TX2_SLAVE_IFIDX=$(ip netns exec "${TXNS}" \
cat /sys/class/net/"$BOND_TX2_SLAVE_IF"/ifindex)
BOND_RX1_SLAVE_IFIDX=$(ip netns exec "${RXNS}" \
cat /sys/class/net/"$BOND_RX1_SLAVE_IF"/ifindex)
BOND_RX2_SLAVE_IFIDX=$(ip netns exec "${RXNS}" \
cat /sys/class/net/"$BOND_RX2_SLAVE_IF"/ifindex)
exec {TXNS_FD}</var/run/netns/"${TXNS}"
exec {RXNS_FD}</var/run/netns/"${RXNS}"
# Linking TX ifaces to the RX ones (on the other namespace)
echo "${TXNS_FD}:$BOND_TX1_SLAVE_IFIDX $RXNS_FD:$BOND_RX1_SLAVE_IFIDX" \
> "$NSIM_DEV_SYS_LINK"
echo "${TXNS_FD}:$BOND_TX2_SLAVE_IFIDX $RXNS_FD:$BOND_RX2_SLAVE_IFIDX" \
> "$NSIM_DEV_SYS_LINK"
exec {TXNS_FD}<&-
exec {RXNS_FD}<&-
}
function create_all_ifaces() {
# setup_ns function is coming from lib.sh
setup_ns TXNS RXNS
export NAMESPACE="${RXNS}"
# Create two interfaces for RX and two for TX
create_ifaces_bond
# Link netlink ifaces
link_ifaces_bond
}
# configure DSTIF and SRCIF IPs
function configure_ifaces_ips() {
local IP_VERSION=${1:-"ipv4"}
select_ipv4_or_ipv6 "${IP_VERSION}"
ip -n "${RXNS}" addr add "${DSTIP}"/24 dev "${DSTIF}"
ip -n "${RXNS}" link set "${DSTIF}" up
ip -n "${TXNS}" addr add "${SRCIP}"/24 dev "${SRCIF}"
ip -n "${TXNS}" link set "${SRCIF}" up
}
function test_enable_netpoll_on_enslaved_iface() {
echo 0 > "${NETCONS_PATH}"/enabled
# At this stage, BOND_TX1_SLAVE_IF is enslaved to BOND_TX_MAIN_IF, and
# linked to BOND_RX1_SLAVE_IF inside the namespace.
echo "${BOND_TX1_SLAVE_IF}" > "${NETCONS_PATH}"/dev_name
# This should fail with the following message in dmesg:
# netpoll: netconsole: ethX is a slave device, aborting
set +e
enable_netcons_ns 2> /dev/null
set -e
if [[ $(cat "${NETCONS_PATH}"/enabled) -eq 1 ]]
then
echo "test failed: Bonding and netpoll cannot co-exists." >&2
exit "${ksft_fail}"
fi
}
function test_delete_bond_and_reenable_target() {
ip -n "${TXNS}" \
link delete "${BOND_TX_MAIN_IF}" type bond
# BOND_TX1_SLAVE_IF is not attached to a bond interface anymore
# netpoll can be plugged in there
echo "${BOND_TX1_SLAVE_IF}" > "${NETCONS_PATH}"/dev_name
# this should work, since the interface is not enslaved
enable_netcons_ns
if [[ $(cat "${NETCONS_PATH}"/enabled) -eq 0 ]]
then
echo "test failed: Unable to start netpoll on an unbond iface." >&2
exit "${ksft_fail}"
fi
}
# Send a netconsole message to the netconsole target
function test_send_netcons_msg_through_bond_iface() {
# Listen for netconsole port inside the namespace and
# destination interface
listen_port_and_save_to "${OUTPUT_FILE}" "${IP_VERSION}" &
# Wait for socat to start and listen to the port.
wait_for_port "${RXNS}" "${PORT}" "${IP_VERSION}"
# Send the message
echo "${MSG}: ${TARGET}" > /dev/kmsg
# Wait until socat saves the file to disk
busywait "${BUSYWAIT_TIMEOUT}" test -s "${OUTPUT_FILE}"
# Make sure the message was received in the dst part
# and exit
validate_result "${OUTPUT_FILE}" "${FORMAT}"
# kill socat in case it is still running
pkill_socat
}
# BOND_TX1_SLAVE_IF has netconsole enabled on it, bind it to BOND_TX_MAIN_IF.
# Given BOND_TX_MAIN_IF was deleted, recreate it first
function test_enslave_netcons_enabled_iface {
# netconsole got disabled while the interface was down
if [[ $(cat "${NETCONS_PATH}"/enabled) -eq 0 ]]
then
echo "test failed: netconsole expected to be enabled against BOND_TX1_SLAVE_IF" >&2
exit "${ksft_fail}"
fi
# recreate the bonding iface. it got deleted by previous
# test (test_delete_bond_and_reenable_target)
ip -n "${TXNS}" \
link add "${BOND_TX_MAIN_IF}" type bond mode balance-rr
# sub-interface need to be down before attaching to bonding
# This will also disable netconsole.
ip -n "${TXNS}" \
link set "${BOND_TX1_SLAVE_IF}" down
ip -n "${TXNS}" \
link set "${BOND_TX1_SLAVE_IF}" master "${BOND_TX_MAIN_IF}"
ip -n "${TXNS}" \
link set "${BOND_TX_MAIN_IF}" up
# netconsole got disabled while the interface was down
if [[ $(cat "${NETCONS_PATH}"/enabled) -eq 1 ]]
then
echo "test failed: Device is part of a bond iface, cannot have netcons enabled" >&2
exit "${ksft_fail}"
fi
}
# Get netconsole enabled on a bonding interface and attach a second
# sub-interface.
function test_enslave_iface_to_bond {
# BOND_TX_MAIN_IF has only BOND_TX1_SLAVE_IF right now
echo "${BOND_TX_MAIN_IF}" > "${NETCONS_PATH}"/dev_name
enable_netcons_ns
# netcons is attached to bond0 and BOND_TX1_SLAVE_IF is
# part of BOND_TX_MAIN_IF. Attach BOND_TX2_SLAVE_IF to BOND_TX_MAIN_IF.
ip -n "${TXNS}" \
link set "${BOND_TX2_SLAVE_IF}" master "${BOND_TX_MAIN_IF}"
if [[ $(cat "${NETCONS_PATH}"/enabled) -eq 0 ]]
then
echo "test failed: Netconsole should be enabled on bonding interface. Failed" >&2
exit "${ksft_fail}"
fi
}
function test_enslave_iff_disabled_netpoll_iface {
local ret
# Create two interfaces. veth interfaces it known to have
# IFF_DISABLE_NETPOLL set
if ! ip link add "${VETH0}" type veth peer name "${VETH1}"
then
echo "Failed to create veth TX interface. Is CONFIG_VETH set?" >&2
exit "${ksft_skip}"
fi
set +e
# This will print RTNETLINK answers: Device or resource busy
ip link set "${VETH0}" master "${BOND_TX_MAIN_IF}" 2> /dev/null
ret=$?
set -e
if [[ $ret -eq 0 ]]
then
echo "test failed: veth interface could not be enslaved"
exit "${ksft_fail}"
fi
}
# Given that netconsole picks the current net namespace, we need to enable it
# from inside the TXNS namespace
function enable_netcons_ns() {
ip netns exec "${TXNS}" sh -c \
"mount -t configfs configfs /sys/kernel/config && echo 1 > $NETCONS_PATH/enabled"
}
####################
# Tests start here #
####################
# Create regular interfaces using netdevsim and link them
create_all_ifaces
# Setup the bonding interfaces
# BOND_RX_MAIN_IF has BOND_RX{1,2}_SLAVE_IF
# BOND_TX_MAIN_IF has BOND_TX{1,2}_SLAVE_IF
setup_bonding_ifaces
# Configure the ips as BOND_RX1_SLAVE_IF and BOND_TX1_SLAVE_IF
configure_ifaces_ips "${IP_VERSION}"
_create_dynamic_target "${FORMAT}" "${NETCONS_PATH}"
enable_netcons_ns
set_user_data
# Test #1 : Create an bonding interface and attach netpoll into
# the bonding interface. Netconsole/netpoll should work on
# the bonding interface.
test_send_netcons_msg_through_bond_iface
echo "test #1: netpoll on bonding interface worked. Test passed" >&2
# Test #2: Attach netpoll to an enslaved interface
# Try to attach netpoll to an enslaved sub-interface (while still being part of
# a bonding interface), which shouldn't be allowed
test_enable_netpoll_on_enslaved_iface
echo "test #2: netpoll correctly rejected enslaved interface (expected behavior). Test passed." >&2
# Test #3: Unplug the sub-interface from bond and enable netconsole
# Detach the interface from a bonding interface and attach netpoll again
test_delete_bond_and_reenable_target
echo "test #3: Able to attach to an unbound interface. Test passed." >&2
# Test #4: Enslave a sub-interface that had netconsole enabled
# Try to enslave an interface that has netconsole/netpoll enabled.
# Previous test has netconsole enabled in BOND_TX1_SLAVE_IF, try to enslave it
test_enslave_netcons_enabled_iface
echo "test #4: Enslaving an interface with netpoll attached. Test passed." >&2
# Test #5: Enslave a sub-interface to a bonding interface
# Enslave an interface to a bond interface that has netpoll attached
# At this stage, BOND_TX_MAIN_IF is created and BOND_TX1_SLAVE_IF is part of
# it. Netconsole is currently disabled
test_enslave_iface_to_bond
echo "test #5: Enslaving an interface to bond+netpoll. Test passed." >&2
# Test #6: Enslave a IFF_DISABLE_NETPOLL sub-interface to a bonding interface
# At this stage, BOND_TX_MAIN_IF has both sub interface and netconsole is
# enabled. This test will try to enslave an a veth (IFF_DISABLE_NETPOLL) interface
# and it should fail, with netpoll: veth0 doesn't support polling
test_enslave_iff_disabled_netpoll_iface
echo "test #6: Enslaving IFF_DISABLE_NETPOLL ifaces to bond iface is not supported. Test passed." >&2
cleanup_bond
trap - EXIT
exit "${EXIT_STATUS}"

View File

@@ -11,9 +11,11 @@ set -euo pipefail
LIBDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")")
SRCIF="" # to be populated later
SRCIP="" # to be populated later
SRCIP4="192.0.2.1"
SRCIP6="fc00::1"
DSTIF="" # to be populated later
DSTIP="" # to be populated later
DSTIP4="192.0.2.2"
DSTIP6="fc00::2"
@@ -28,17 +30,23 @@ NETCONS_PATH="${NETCONS_CONFIGFS}"/"${TARGET}"
# NAMESPACE will be populated by setup_ns with a random value
NAMESPACE=""
# IDs for netdevsim
# IDs for netdevsim. We either use NSIM_DEV_{1,2}_ID for standard test
# or NSIM_BOND_{T,R}X_{1,2} for the bonding tests. Not both at the
# same time.
NSIM_DEV_1_ID=$((256 + RANDOM % 256))
NSIM_DEV_2_ID=$((512 + RANDOM % 256))
NSIM_BOND_TX_1=$((768 + RANDOM % 256))
NSIM_BOND_TX_2=$((1024 + RANDOM % 256))
NSIM_BOND_RX_1=$((1280 + RANDOM % 256))
NSIM_BOND_RX_2=$((1536 + RANDOM % 256))
NSIM_DEV_SYS_NEW="/sys/bus/netdevsim/new_device"
NSIM_DEV_SYS_LINK="/sys/bus/netdevsim/link_device"
# Used to create and delete namespaces
source "${LIBDIR}"/../../../../net/lib.sh
# Create netdevsim interfaces
create_ifaces() {
echo "$NSIM_DEV_2_ID" > "$NSIM_DEV_SYS_NEW"
echo "$NSIM_DEV_1_ID" > "$NSIM_DEV_SYS_NEW"
udevadm settle 2> /dev/null || true
@@ -113,31 +121,38 @@ function set_network() {
configure_ip
}
function create_dynamic_target() {
local FORMAT=${1:-"extended"}
function _create_dynamic_target() {
local FORMAT="${1:?FORMAT parameter required}"
local NCPATH="${2:?NCPATH parameter required}"
DSTMAC=$(ip netns exec "${NAMESPACE}" \
ip link show "${DSTIF}" | awk '/ether/ {print $2}')
# Create a dynamic target
mkdir "${NETCONS_PATH}"
mkdir "${NCPATH}"
echo "${DSTIP}" > "${NETCONS_PATH}"/remote_ip
echo "${SRCIP}" > "${NETCONS_PATH}"/local_ip
echo "${DSTMAC}" > "${NETCONS_PATH}"/remote_mac
echo "${SRCIF}" > "${NETCONS_PATH}"/dev_name
echo "${DSTIP}" > "${NCPATH}"/remote_ip
echo "${SRCIP}" > "${NCPATH}"/local_ip
echo "${DSTMAC}" > "${NCPATH}"/remote_mac
echo "${SRCIF}" > "${NCPATH}"/dev_name
if [ "${FORMAT}" == "basic" ]
then
# Basic target does not support release
echo 0 > "${NETCONS_PATH}"/release
echo 0 > "${NETCONS_PATH}"/extended
echo 0 > "${NCPATH}"/release
echo 0 > "${NCPATH}"/extended
elif [ "${FORMAT}" == "extended" ]
then
echo 1 > "${NETCONS_PATH}"/extended
echo 1 > "${NCPATH}"/extended
fi
}
echo 1 > "${NETCONS_PATH}"/enabled
function create_dynamic_target() {
local FORMAT=${1:-"extended"}
local NCPATH=${2:-"$NETCONS_PATH"}
_create_dynamic_target "${FORMAT}" "${NCPATH}"
echo 1 > "${NCPATH}"/enabled
# This will make sure that the kernel was able to
# load the netconsole driver configuration. The console message
@@ -185,14 +200,26 @@ function do_cleanup() {
echo "${DEFAULT_PRINTK_VALUES}" > /proc/sys/kernel/printk
}
function cleanup() {
function cleanup_netcons() {
# delete netconsole dynamic reconfiguration
echo 0 > "${NETCONS_PATH}"/enabled
# do not fail if the target is already disabled
if [[ ! -d "${NETCONS_PATH}" ]]
then
# in some cases this is called before netcons path is created
return
fi
if [[ $(cat "${NETCONS_PATH}"/enabled) != 0 ]]
then
echo 0 > "${NETCONS_PATH}"/enabled || true
fi
# Remove all the keys that got created during the selftest
find "${NETCONS_PATH}/userdata/" -mindepth 1 -type d -delete
# Remove the configfs entry
rmdir "${NETCONS_PATH}"
}
function cleanup() {
cleanup_netcons
do_cleanup
}
@@ -369,3 +396,24 @@ function wait_for_port() {
# more frequently on IPv6
sleep 1
}
# Clean up netdevsim ifaces created for bonding test
function cleanup_bond_nsim() {
ip -n "${TXNS}" \
link delete "${BOND_TX_MAIN_IF}" type bond || true
ip -n "${RXNS}" \
link delete "${BOND_RX_MAIN_IF}" type bond || true
cleanup_netdevsim "$NSIM_BOND_TX_1"
cleanup_netdevsim "$NSIM_BOND_TX_2"
cleanup_netdevsim "$NSIM_BOND_RX_1"
cleanup_netdevsim "$NSIM_BOND_RX_2"
}
# cleanup tests that use bonding interfaces
function cleanup_bond() {
cleanup_netcons
cleanup_bond_nsim
cleanup_all_ns
ip link delete "${VETH0}" || true
}

View File

@@ -0,0 +1,130 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: GPL-2.0
# Repeatedly send kernel messages, toggles netconsole targets on and off,
# creates and deletes targets in parallel, and toggles the source interface to
# simulate stress conditions.
#
# This test aims to verify the robustness of netconsole under dynamic
# configurations and concurrent operations.
#
# The major goal is to run this test with LOCKDEP, Kmemleak and KASAN to make
# sure no issues is reported.
#
# Author: Breno Leitao <leitao@debian.org>
set -euo pipefail
SCRIPTDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")")
source "${SCRIPTDIR}"/lib/sh/lib_netcons.sh
# Number of times the main loop run
ITERATIONS=${1:-150}
# Only test extended format
FORMAT="extended"
# And ipv6 only
IP_VERSION="ipv6"
# Create, enable and delete some targets.
create_and_delete_random_target() {
COUNT=2
RND_PREFIX=$(mktemp -u netcons_rnd_XXXX_)
if [ -d "${NETCONS_CONFIGFS}/${RND_PREFIX}${COUNT}" ] || \
[ -d "${NETCONS_CONFIGFS}/${RND_PREFIX}0" ]; then
echo "Function didn't finish yet, skipping it." >&2
return
fi
# enable COUNT targets
for i in $(seq ${COUNT})
do
RND_TARGET="${RND_PREFIX}"${i}
RND_TARGET_PATH="${NETCONS_CONFIGFS}"/"${RND_TARGET}"
# Basic population so the target can come up
_create_dynamic_target "${FORMAT}" "${RND_TARGET_PATH}"
done
echo "netconsole selftest: ${COUNT} additional targets were created" > /dev/kmsg
# disable them all
for i in $(seq ${COUNT})
do
RND_TARGET="${RND_PREFIX}"${i}
RND_TARGET_PATH="${NETCONS_CONFIGFS}"/"${RND_TARGET}"
if [[ $(cat "${RND_TARGET_PATH}/enabled") -eq 1 ]]
then
echo 0 > "${RND_TARGET_PATH}"/enabled
fi
rmdir "${RND_TARGET_PATH}"
done
}
# Disable and enable the target mid-air, while messages
# are being transmitted.
toggle_netcons_target() {
for i in $(seq 2)
do
if [ ! -d "${NETCONS_PATH}" ]
then
break
fi
echo 0 > "${NETCONS_PATH}"/enabled 2> /dev/null || true
# Try to enable a bit harder, given it might fail to enable
# Write to `enabled` might fail depending on the lock, which is
# highly contentious here
for _ in $(seq 5)
do
echo 1 > "${NETCONS_PATH}"/enabled 2> /dev/null || true
done
done
}
toggle_iface(){
ip link set "${SRCIF}" down
ip link set "${SRCIF}" up
}
# Start here
modprobe netdevsim 2> /dev/null || true
modprobe netconsole 2> /dev/null || true
# Check for basic system dependency and exit if not found
check_for_dependencies
# Set current loglevel to KERN_INFO(6), and default to KERN_NOTICE(5)
echo "6 5" > /proc/sys/kernel/printk
# Remove the namespace, interfaces and netconsole target on exit
trap cleanup EXIT
# Create one namespace and two interfaces
set_network "${IP_VERSION}"
# Create a dynamic target for netconsole
create_dynamic_target "${FORMAT}"
for i in $(seq "$ITERATIONS")
do
for _ in $(seq 10)
do
echo "${MSG}: ${TARGET} ${i}" > /dev/kmsg
done
wait
if (( i % 30 == 0 )); then
toggle_netcons_target &
fi
if (( i % 50 == 0 )); then
# create some targets, enable them, send msg and disable
# all in a parallel thread
create_and_delete_random_target &
fi
if (( i % 70 == 0 )); then
toggle_iface &
fi
done
wait
exit "${EXIT_STATUS}"

View File

@@ -176,6 +176,8 @@ run_test()
local rcv_dmac=$(mac_get $rcv_if_name)
local should_receive
setup_wait
tcpdump_start $rcv_if_name
mc_route_prepare $send_if_name

View File

@@ -710,8 +710,14 @@ static int copyfd_io_poll(int infd, int peerfd, int outfd,
bw = do_rnd_write(peerfd, winfo->buf + winfo->off, winfo->len);
if (bw < 0) {
if (cfg_rcv_trunc)
return 0;
/* expected reset, continue to read */
if (cfg_rcv_trunc &&
(errno == ECONNRESET ||
errno == EPIPE)) {
fds.events &= ~POLLOUT;
continue;
}
perror("write");
return 111;
}
@@ -737,8 +743,10 @@ static int copyfd_io_poll(int infd, int peerfd, int outfd,
}
if (fds.revents & (POLLERR | POLLNVAL)) {
if (cfg_rcv_trunc)
return 0;
if (cfg_rcv_trunc) {
fds.events &= ~(POLLERR | POLLNVAL);
continue;
}
fprintf(stderr, "Unexpected revents: "
"POLLERR/POLLNVAL(%x)\n", fds.revents);
return 5;
@@ -1433,7 +1441,7 @@ static void parse_opts(int argc, char **argv)
*/
if (cfg_truncate < 0) {
cfg_rcv_trunc = true;
signal(SIGPIPE, handle_signal);
signal(SIGPIPE, SIG_IGN);
}
break;
case 'j':

View File

@@ -492,7 +492,7 @@ do_transfer()
"than expected (${expect_synrx})"
retc=1
fi
if [ ${stat_ackrx_now_l} -lt ${expect_ackrx} ] && [ ${stat_ooo_now} -eq 0 ]; then
if [ ${stat_ackrx_now_l} -lt ${expect_ackrx} ]; then
if [ ${stat_ooo_now} -eq 0 ]; then
mptcp_lib_pr_fail "lower MPC ACK rx (${stat_ackrx_now_l})" \
"than expected (${expect_ackrx})"

View File

@@ -2532,7 +2532,7 @@ remove_tests()
if reset "remove single subflow"; then
pm_nl_set_limits $ns1 0 1
pm_nl_set_limits $ns2 0 1
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow,backup
addr_nr_ns2=-1 speed=slow \
run_tests $ns1 $ns2 10.0.1.1
chk_join_nr 1 1 1
@@ -2545,8 +2545,8 @@ remove_tests()
if reset "remove multiple subflows"; then
pm_nl_set_limits $ns1 0 2
pm_nl_set_limits $ns2 0 2
pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow
pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow,backup
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow,backup
addr_nr_ns2=-2 speed=slow \
run_tests $ns1 $ns2 10.0.1.1
chk_join_nr 2 2 2
@@ -2557,7 +2557,7 @@ remove_tests()
# single address, remove
if reset "remove single address"; then
pm_nl_set_limits $ns1 0 1
pm_nl_add_endpoint $ns1 10.0.2.1 flags signal
pm_nl_add_endpoint $ns1 10.0.2.1 flags signal,backup
pm_nl_set_limits $ns2 1 1
addr_nr_ns1=-1 speed=slow \
run_tests $ns1 $ns2 10.0.1.1
@@ -2570,9 +2570,9 @@ remove_tests()
# subflow and signal, remove
if reset "remove subflow and signal"; then
pm_nl_set_limits $ns1 0 2
pm_nl_add_endpoint $ns1 10.0.2.1 flags signal
pm_nl_add_endpoint $ns1 10.0.2.1 flags signal,backup
pm_nl_set_limits $ns2 1 2
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow,backup
addr_nr_ns1=-1 addr_nr_ns2=-1 speed=slow \
run_tests $ns1 $ns2 10.0.1.1
chk_join_nr 2 2 2
@@ -2584,10 +2584,10 @@ remove_tests()
# subflows and signal, remove
if reset "remove subflows and signal"; then
pm_nl_set_limits $ns1 0 3
pm_nl_add_endpoint $ns1 10.0.2.1 flags signal
pm_nl_add_endpoint $ns1 10.0.2.1 flags signal,backup
pm_nl_set_limits $ns2 1 3
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow
pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow,backup
pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow,backup
addr_nr_ns1=-1 addr_nr_ns2=-2 speed=10 \
run_tests $ns1 $ns2 10.0.1.1
chk_join_nr 3 3 3
@@ -2599,9 +2599,9 @@ remove_tests()
# addresses remove
if reset "remove addresses"; then
pm_nl_set_limits $ns1 3 3
pm_nl_add_endpoint $ns1 10.0.2.1 flags signal id 250
pm_nl_add_endpoint $ns1 10.0.3.1 flags signal
pm_nl_add_endpoint $ns1 10.0.4.1 flags signal
pm_nl_add_endpoint $ns1 10.0.2.1 flags signal,backup id 250
pm_nl_add_endpoint $ns1 10.0.3.1 flags signal,backup
pm_nl_add_endpoint $ns1 10.0.4.1 flags signal,backup
pm_nl_set_limits $ns2 3 3
addr_nr_ns1=-3 speed=10 \
run_tests $ns1 $ns2 10.0.1.1
@@ -2614,10 +2614,10 @@ remove_tests()
# invalid addresses remove
if reset "remove invalid addresses"; then
pm_nl_set_limits $ns1 3 3
pm_nl_add_endpoint $ns1 10.0.12.1 flags signal
pm_nl_add_endpoint $ns1 10.0.12.1 flags signal,backup
# broadcast IP: no packet for this address will be received on ns1
pm_nl_add_endpoint $ns1 224.0.0.1 flags signal
pm_nl_add_endpoint $ns1 10.0.3.1 flags signal
pm_nl_add_endpoint $ns1 224.0.0.1 flags signal,backup
pm_nl_add_endpoint $ns1 10.0.3.1 flags signal,backup
pm_nl_set_limits $ns2 2 2
addr_nr_ns1=-3 speed=10 \
run_tests $ns1 $ns2 10.0.1.1
@@ -2631,10 +2631,10 @@ remove_tests()
# subflows and signal, flush
if reset "flush subflows and signal"; then
pm_nl_set_limits $ns1 0 3
pm_nl_add_endpoint $ns1 10.0.2.1 flags signal
pm_nl_add_endpoint $ns1 10.0.2.1 flags signal,backup
pm_nl_set_limits $ns2 1 3
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow
pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow,backup
pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow,backup
addr_nr_ns1=-8 addr_nr_ns2=-8 speed=slow \
run_tests $ns1 $ns2 10.0.1.1
chk_join_nr 3 3 3
@@ -2647,9 +2647,9 @@ remove_tests()
if reset "flush subflows"; then
pm_nl_set_limits $ns1 3 3
pm_nl_set_limits $ns2 3 3
pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow id 150
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow
pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow
pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow,backup id 150
pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow,backup
pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow,backup
addr_nr_ns1=-8 addr_nr_ns2=-8 speed=slow \
run_tests $ns1 $ns2 10.0.1.1
chk_join_nr 3 3 3
@@ -2666,9 +2666,9 @@ remove_tests()
# addresses flush
if reset "flush addresses"; then
pm_nl_set_limits $ns1 3 3
pm_nl_add_endpoint $ns1 10.0.2.1 flags signal id 250
pm_nl_add_endpoint $ns1 10.0.3.1 flags signal
pm_nl_add_endpoint $ns1 10.0.4.1 flags signal
pm_nl_add_endpoint $ns1 10.0.2.1 flags signal,backup id 250
pm_nl_add_endpoint $ns1 10.0.3.1 flags signal,backup
pm_nl_add_endpoint $ns1 10.0.4.1 flags signal,backup
pm_nl_set_limits $ns2 3 3
addr_nr_ns1=-8 addr_nr_ns2=-8 speed=slow \
run_tests $ns1 $ns2 10.0.1.1
@@ -2681,9 +2681,9 @@ remove_tests()
# invalid addresses flush
if reset "flush invalid addresses"; then
pm_nl_set_limits $ns1 3 3
pm_nl_add_endpoint $ns1 10.0.12.1 flags signal
pm_nl_add_endpoint $ns1 10.0.3.1 flags signal
pm_nl_add_endpoint $ns1 10.0.14.1 flags signal
pm_nl_add_endpoint $ns1 10.0.12.1 flags signal,backup
pm_nl_add_endpoint $ns1 10.0.3.1 flags signal,backup
pm_nl_add_endpoint $ns1 10.0.14.1 flags signal,backup
pm_nl_set_limits $ns2 3 3
addr_nr_ns1=-8 speed=slow \
run_tests $ns1 $ns2 10.0.1.1
@@ -3806,7 +3806,7 @@ userspace_tests()
continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
set_userspace_pm $ns1
pm_nl_set_limits $ns2 2 2
{ speed=5 \
{ test_linkfail=128 speed=5 \
run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null
local tests_pid=$!
wait_mpj $ns1
@@ -3831,7 +3831,7 @@ userspace_tests()
chk_mptcp_info subflows 0 subflows 0
chk_subflows_total 1 1
kill_events_pids
mptcp_lib_kill_wait $tests_pid
mptcp_lib_kill_group_wait $tests_pid
fi
# userspace pm create destroy subflow
@@ -3839,7 +3839,7 @@ userspace_tests()
continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
set_userspace_pm $ns2
pm_nl_set_limits $ns1 0 1
{ speed=5 \
{ test_linkfail=128 speed=5 \
run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null
local tests_pid=$!
wait_mpj $ns2
@@ -3859,7 +3859,7 @@ userspace_tests()
chk_mptcp_info subflows 0 subflows 0
chk_subflows_total 1 1
kill_events_pids
mptcp_lib_kill_wait $tests_pid
mptcp_lib_kill_group_wait $tests_pid
fi
# userspace pm create id 0 subflow
@@ -3867,7 +3867,7 @@ userspace_tests()
continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
set_userspace_pm $ns2
pm_nl_set_limits $ns1 0 1
{ speed=5 \
{ test_linkfail=128 speed=5 \
run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null
local tests_pid=$!
wait_mpj $ns2
@@ -3880,7 +3880,7 @@ userspace_tests()
chk_mptcp_info subflows 1 subflows 1
chk_subflows_total 2 2
kill_events_pids
mptcp_lib_kill_wait $tests_pid
mptcp_lib_kill_group_wait $tests_pid
fi
# userspace pm remove initial subflow
@@ -3888,7 +3888,7 @@ userspace_tests()
continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
set_userspace_pm $ns2
pm_nl_set_limits $ns1 0 1
{ speed=5 \
{ test_linkfail=128 speed=5 \
run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null
local tests_pid=$!
wait_mpj $ns2
@@ -3904,7 +3904,7 @@ userspace_tests()
chk_mptcp_info subflows 1 subflows 1
chk_subflows_total 1 1
kill_events_pids
mptcp_lib_kill_wait $tests_pid
mptcp_lib_kill_group_wait $tests_pid
fi
# userspace pm send RM_ADDR for ID 0
@@ -3912,7 +3912,7 @@ userspace_tests()
continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
set_userspace_pm $ns1
pm_nl_set_limits $ns2 1 1
{ speed=5 \
{ test_linkfail=128 speed=5 \
run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null
local tests_pid=$!
wait_mpj $ns1
@@ -3930,7 +3930,7 @@ userspace_tests()
chk_mptcp_info subflows 1 subflows 1
chk_subflows_total 1 1
kill_events_pids
mptcp_lib_kill_wait $tests_pid
mptcp_lib_kill_group_wait $tests_pid
fi
}
@@ -3943,7 +3943,7 @@ endpoint_tests()
pm_nl_set_limits $ns1 2 2
pm_nl_set_limits $ns2 2 2
pm_nl_add_endpoint $ns1 10.0.2.1 flags signal
{ speed=slow \
{ test_linkfail=128 speed=slow \
run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null
local tests_pid=$!
@@ -3960,7 +3960,7 @@ endpoint_tests()
pm_nl_add_endpoint $ns2 10.0.2.2 flags signal
pm_nl_check_endpoint "modif is allowed" \
$ns2 10.0.2.2 id 1 flags signal
mptcp_lib_kill_wait $tests_pid
mptcp_lib_kill_group_wait $tests_pid
fi
if reset_with_tcp_filter "delete and re-add" ns2 10.0.3.2 REJECT OUTPUT &&
@@ -3970,7 +3970,7 @@ endpoint_tests()
pm_nl_set_limits $ns2 0 3
pm_nl_add_endpoint $ns2 10.0.1.2 id 1 dev ns2eth1 flags subflow
pm_nl_add_endpoint $ns2 10.0.2.2 id 2 dev ns2eth2 flags subflow
{ test_linkfail=4 speed=5 \
{ test_linkfail=128 speed=5 \
run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null
local tests_pid=$!
@@ -4015,7 +4015,7 @@ endpoint_tests()
chk_mptcp_info subflows 3 subflows 3
done
mptcp_lib_kill_wait $tests_pid
mptcp_lib_kill_group_wait $tests_pid
kill_events_pids
chk_evt_nr ns1 MPTCP_LIB_EVENT_LISTENER_CREATED 1
@@ -4048,7 +4048,7 @@ endpoint_tests()
# broadcast IP: no packet for this address will be received on ns1
pm_nl_add_endpoint $ns1 224.0.0.1 id 2 flags signal
pm_nl_add_endpoint $ns1 10.0.1.1 id 42 flags signal
{ test_linkfail=4 speed=5 \
{ test_linkfail=128 speed=5 \
run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null
local tests_pid=$!
@@ -4089,7 +4089,7 @@ endpoint_tests()
wait_mpj $ns2
chk_subflow_nr "after re-re-add ID 0" 3
chk_mptcp_info subflows 3 subflows 3
mptcp_lib_kill_wait $tests_pid
mptcp_lib_kill_group_wait $tests_pid
kill_events_pids
chk_evt_nr ns1 MPTCP_LIB_EVENT_LISTENER_CREATED 1
@@ -4121,7 +4121,7 @@ endpoint_tests()
# broadcast IP: no packet for this address will be received on ns1
pm_nl_add_endpoint $ns1 224.0.0.1 id 2 flags signal
pm_nl_add_endpoint $ns2 10.0.3.2 id 3 flags subflow
{ test_linkfail=4 speed=20 \
{ test_linkfail=128 speed=20 \
run_tests $ns1 $ns2 10.0.1.1 & } 2>/dev/null
local tests_pid=$!
@@ -4137,7 +4137,7 @@ endpoint_tests()
wait_mpj $ns2
pm_nl_add_endpoint $ns1 10.0.3.1 id 2 flags signal
wait_mpj $ns2
mptcp_lib_kill_wait $tests_pid
mptcp_lib_kill_group_wait $tests_pid
join_syn_tx=3 join_connect_err=1 \
chk_join_nr 2 2 2

View File

@@ -350,6 +350,27 @@ mptcp_lib_kill_wait() {
wait "${1}" 2>/dev/null
}
# $1: PID
mptcp_lib_pid_list_children() {
local curr="${1}"
# evoke 'ps' only once
local pids="${2:-"$(ps o pid,ppid)"}"
echo "${curr}"
local pid
for pid in $(echo "${pids}" | awk "\$2 == ${curr} { print \$1 }"); do
mptcp_lib_pid_list_children "${pid}" "${pids}"
done
}
# $1: PID
mptcp_lib_kill_group_wait() {
# Some users might not have procps-ng: cannot use "kill -- -PID"
mptcp_lib_pid_list_children "${1}" | xargs -r kill &>/dev/null
wait "${1}" 2>/dev/null
}
# $1: IP address
mptcp_lib_is_v6() {
[ -z "${1##*:*}" ]

View File

@@ -961,5 +961,49 @@
"teardown": [
"$TC qdisc del dev $DUMMY root"
]
},
{
"id": "4989",
"name": "Try to add an fq child to an ingress qdisc",
"category": [
"qdisc",
"ingress"
],
"plugins": {
"requires": "nsPlugin"
},
"setup": [
"$TC qdisc add dev $DUMMY handle ffff:0 ingress"
],
"cmdUnderTest": "$TC qdisc add dev $DUMMY parent ffff:0 handle ffe0:0 fq",
"expExitCode": "2",
"verifyCmd": "$TC -j qdisc ls dev $DUMMY handle ffe0:",
"matchJSON": [],
"matchCount": "1",
"teardown": [
"$TC qdisc del dev $DUMMY ingress"
]
},
{
"id": "c2b0",
"name": "Try to add an fq child to a clsact qdisc",
"category": [
"qdisc",
"ingress"
],
"plugins": {
"requires": "nsPlugin"
},
"setup": [
"$TC qdisc add dev $DUMMY handle ffff:0 clsact"
],
"cmdUnderTest": "$TC qdisc add dev $DUMMY parent ffff:0 handle ffe0:0 fq",
"expExitCode": "2",
"verifyCmd": "$TC -j qdisc ls dev $DUMMY handle ffe0:",
"matchJSON": [],
"matchCount": "1",
"teardown": [
"$TC qdisc del dev $DUMMY clsact"
]
}
]