Including fixes from Bluetooth.

Current release - regressions:
 
   - tcp: refine sk_rcvbuf increase for ooo packets
 
   - bluetooth: fix attempting to send HCI_Disconnect to BIS handle
 
   - rxrpc: fix over large frame size warning
 
   - eth: bcmgenet: initialize u64 stats seq counter
 
 Previous releases - regressions:
 
   - tcp: correct signedness in skb remaining space calculation
 
   - sched: abort __tc_modify_qdisc if parent class does not exist
 
   - vsock: fix transport_{g2h,h2g} TOCTOU
 
   - rxrpc: fix bug due to prealloc collision
 
   - tipc: fix use-after-free in tipc_conn_close().
 
   - bluetooth: fix not marking Broadcast Sink BIS as connected
 
   - phy: qca808x: fix WoL issue by utilizing at8031_set_wol()
 
   - eth: am65-cpsw-nuss: fix skb size by accounting for skb_shared_info
 
 Previous releases - always broken:
 
   - netlink: fix wraparounds of sk->sk_rmem_alloc.
 
   - atm: fix infinite recursive call of clip_push().
 
   - eth: stmmac: fix interrupt handling for level-triggered mode in DWC_XGMAC2
 
   - eth: rtsn: fix a null pointer dereference in rtsn_probe()
 
 Signed-off-by: Paolo Abeni <pabeni@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQJGBAABCAAwFiEEg1AjqC77wbdLX2LbKSR5jcyPE6QFAmhvtRwSHHBhYmVuaUBy
 ZWRoYXQuY29tAAoJECkkeY3MjxOke6wP/iqvFgmSTHwmp+KvgV2RooqPcspstVM4
 hiQ4UkdtShGzfnf+YulpNgXTefVvzPpJ+yqMr+Kh5+I5rxCdE7rmm7jnwa7w3rK1
 3LpvwWPRbZB4FNBY3RusipbWaWmH+OW1kmXNSZ2GQJVydWlk4ebW0EES1ryQWTvh
 XdA6/w+qrlpBPxk7gP8ySrxOPm817o5O1FYZfRi1HaOKKmRVcxAupaiS3dkIMRIu
 6zKlrg83mnD0AkO5c4fILZxo3rrmYM94uTxxIezxfsDfL4PHiWbZjuIe53qJaraO
 FBC1GZ+dsqRXwIxdBvLixeWJxVpJs9ZpWTj+aIOkOU+voYRMDP41/NhDZv8Xy1BT
 p5u0kjwOLIF+ELw63+klGYku9LWQpxYNnRNqRTBSbIu4rQTPgNkpi38NOgwt2sPE
 u3p68nK78WMEj6eAHws6bkS/udaQD9TqR1Kgt27vHz/LakdyTTanELtsN6rK6wdp
 dwX09rEQJk1QsWCd3vW5OHQMep7qhMBtCtqkuMNZlzt6PjzNpDNjKnued5qNn95i
 nw/mdZI2WtvbkTDLioNOb9UuaqMUT2G1MCl2ywUNcPTNK8nPNOjIS9KVCkkMrLfk
 +NvdXO94iz7l5Wlxd6/c9LA+8kHgWaZFD5PEE0ApvfEi/FyRLSMxnmWOHE6vRCEk
 1+AwFSWWM3/X
 =GD9v
 -----END PGP SIGNATURE-----

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

Pull networking fixes from Paolo Abeni:
 "Including fixes from Bluetooth.

  Current release - regressions:

   - tcp: refine sk_rcvbuf increase for ooo packets

   - bluetooth: fix attempting to send HCI_Disconnect to BIS handle

   - rxrpc: fix over large frame size warning

   - eth: bcmgenet: initialize u64 stats seq counter

  Previous releases - regressions:

   - tcp: correct signedness in skb remaining space calculation

   - sched: abort __tc_modify_qdisc if parent class does not exist

   - vsock: fix transport_{g2h,h2g} TOCTOU

   - rxrpc: fix bug due to prealloc collision

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

   - bluetooth: fix not marking Broadcast Sink BIS as connected

   - phy: qca808x: fix WoL issue by utilizing at8031_set_wol()

   - eth: am65-cpsw-nuss: fix skb size by accounting for skb_shared_info

  Previous releases - always broken:

   - netlink: fix wraparounds of sk->sk_rmem_alloc.

   - atm: fix infinite recursive call of clip_push().

   - eth:
      - stmmac: fix interrupt handling for level-triggered mode in DWC_XGMAC2
      - rtsn: fix a null pointer dereference in rtsn_probe()"

* tag 'net-6.16-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (37 commits)
  net/sched: sch_qfq: Fix null-deref in agg_dequeue
  rxrpc: Fix oops due to non-existence of prealloc backlog struct
  rxrpc: Fix bug due to prealloc collision
  MAINTAINERS: remove myself as netronome maintainer
  selftests/net: packetdrill: add tcp_ooo-before-and-after-accept.pkt
  tcp: refine sk_rcvbuf increase for ooo packets
  net/sched: Abort __tc_modify_qdisc if parent class does not exist
  net: ethernet: ti: am65-cpsw-nuss: Fix skb size by accounting for skb_shared_info
  net: thunderx: avoid direct MTU assignment after WRITE_ONCE()
  selftests/tc-testing: Create test case for UAF scenario with DRR/NETEM/BLACKHOLE chain
  atm: clip: Fix NULL pointer dereference in vcc_sendmsg()
  atm: clip: Fix infinite recursive call of clip_push().
  atm: clip: Fix memory leak of struct clip_vcc.
  atm: clip: Fix potential null-ptr-deref in to_atmarpd().
  net: phy: smsc: Fix link failure in forced mode with Auto-MDIX
  net: phy: smsc: Force predictable MDI-X state on LAN87xx
  net: phy: smsc: Fix Auto-MDIX configuration when disabled by strap
  net: stmmac: Fix interrupt handling for level-triggered mode in DWC_XGMAC2
  rxrpc: Fix over large frame size warning
  net: airoha: Fix an error handling path in airoha_probe()
  ...
This commit is contained in:
Linus Torvalds 2025-07-10 09:18:53 -07:00
commit bc9ff192a6
33 changed files with 425 additions and 179 deletions

View File

@ -23,7 +23,7 @@ properties:
- allwinner,sun20i-d1-emac
- allwinner,sun50i-h6-emac
- allwinner,sun50i-h616-emac0
- allwinner,sun55i-a523-emac0
- allwinner,sun55i-a523-gmac0
- const: allwinner,sun50i-a64-emac
reg:

View File

@ -17224,10 +17224,10 @@ F: drivers/rtc/rtc-ntxec.c
F: include/linux/mfd/ntxec.h
NETRONOME ETHERNET DRIVERS
M: Louis Peens <louis.peens@corigine.com>
R: Jakub Kicinski <kuba@kernel.org>
R: Simon Horman <horms@kernel.org>
L: oss-drivers@corigine.com
S: Maintained
S: Odd Fixes
F: drivers/net/ethernet/netronome/
NETWORK BLOCK DEVICE (NBD)

View File

@ -2984,6 +2984,7 @@ static int airoha_probe(struct platform_device *pdev)
error_napi_stop:
for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
airoha_qdma_stop_napi(&eth->qdma[i]);
airoha_ppe_deinit(eth);
error_hw_cleanup:
for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
airoha_hw_cleanup(&eth->qdma[i]);

View File

@ -11607,11 +11607,9 @@ static void bnxt_free_irq(struct bnxt *bp)
static int bnxt_request_irq(struct bnxt *bp)
{
struct cpu_rmap *rmap = NULL;
int i, j, rc = 0;
unsigned long flags = 0;
#ifdef CONFIG_RFS_ACCEL
struct cpu_rmap *rmap;
#endif
rc = bnxt_setup_int_mode(bp);
if (rc) {
@ -11632,15 +11630,15 @@ static int bnxt_request_irq(struct bnxt *bp)
int map_idx = bnxt_cp_num_to_irq_num(bp, i);
struct bnxt_irq *irq = &bp->irq_tbl[map_idx];
#ifdef CONFIG_RFS_ACCEL
if (rmap && bp->bnapi[i]->rx_ring) {
if (IS_ENABLED(CONFIG_RFS_ACCEL) &&
rmap && bp->bnapi[i]->rx_ring) {
rc = irq_cpu_rmap_add(rmap, irq->vector);
if (rc)
netdev_warn(bp->dev, "failed adding irq rmap for ring %d\n",
j);
j++;
}
#endif
rc = request_irq(irq->vector, irq->handler, flags, irq->name,
bp->bnapi[i]);
if (rc)

View File

@ -4092,6 +4092,12 @@ static int bcmgenet_probe(struct platform_device *pdev)
for (i = 0; i <= priv->hw_params->rx_queues; i++)
priv->rx_rings[i].rx_max_coalesced_frames = 1;
/* Initialize u64 stats seq counter for 32bit machines */
for (i = 0; i <= priv->hw_params->rx_queues; i++)
u64_stats_init(&priv->rx_rings[i].stats64.syncp);
for (i = 0; i <= priv->hw_params->tx_queues; i++)
u64_stats_init(&priv->tx_rings[i].stats64.syncp);
/* libphy will determine the link state */
netif_carrier_off(dev);

View File

@ -1578,7 +1578,6 @@ napi_del:
static int nicvf_change_mtu(struct net_device *netdev, int new_mtu)
{
struct nicvf *nic = netdev_priv(netdev);
int orig_mtu = netdev->mtu;
/* For now just support only the usual MTU sized frames,
* plus some headroom for VLAN, QinQ.
@ -1589,15 +1588,10 @@ static int nicvf_change_mtu(struct net_device *netdev, int new_mtu)
return -EINVAL;
}
WRITE_ONCE(netdev->mtu, new_mtu);
if (!netif_running(netdev))
return 0;
if (nicvf_update_hw_max_frs(nic, new_mtu)) {
netdev->mtu = orig_mtu;
if (netif_running(netdev) && nicvf_update_hw_max_frs(nic, new_mtu))
return -EINVAL;
}
WRITE_ONCE(netdev->mtu, new_mtu);
return 0;
}

View File

@ -1259,7 +1259,12 @@ static int rtsn_probe(struct platform_device *pdev)
priv = netdev_priv(ndev);
priv->pdev = pdev;
priv->ndev = ndev;
priv->ptp_priv = rcar_gen4_ptp_alloc(pdev);
if (!priv->ptp_priv) {
ret = -ENOMEM;
goto error_free;
}
spin_lock_init(&priv->lock);
platform_set_drvdata(pdev, priv);

View File

@ -364,19 +364,17 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv,
}
/* TX/RX NORMAL interrupts */
if (likely(intr_status & XGMAC_NIS)) {
if (likely(intr_status & XGMAC_RI)) {
u64_stats_update_begin(&stats->syncp);
u64_stats_inc(&stats->rx_normal_irq_n[chan]);
u64_stats_update_end(&stats->syncp);
ret |= handle_rx;
}
if (likely(intr_status & (XGMAC_TI | XGMAC_TBU))) {
u64_stats_update_begin(&stats->syncp);
u64_stats_inc(&stats->tx_normal_irq_n[chan]);
u64_stats_update_end(&stats->syncp);
ret |= handle_tx;
}
if (likely(intr_status & XGMAC_RI)) {
u64_stats_update_begin(&stats->syncp);
u64_stats_inc(&stats->rx_normal_irq_n[chan]);
u64_stats_update_end(&stats->syncp);
ret |= handle_rx;
}
if (likely(intr_status & (XGMAC_TI | XGMAC_TBU))) {
u64_stats_update_begin(&stats->syncp);
u64_stats_inc(&stats->tx_normal_irq_n[chan]);
u64_stats_update_end(&stats->syncp);
ret |= handle_tx;
}
/* Clear interrupts */

View File

@ -856,8 +856,6 @@ static struct sk_buff *am65_cpsw_build_skb(void *page_addr,
{
struct sk_buff *skb;
len += AM65_CPSW_HEADROOM;
skb = build_skb(page_addr, len);
if (unlikely(!skb))
return NULL;
@ -1344,7 +1342,7 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_rx_flow *flow,
}
skb = am65_cpsw_build_skb(page_addr, ndev,
AM65_CPSW_MAX_PACKET_SIZE, headroom);
PAGE_SIZE, headroom);
if (unlikely(!skb)) {
new_page = page;
goto requeue;

View File

@ -26,9 +26,6 @@
#define AT803X_LED_CONTROL 0x18
#define AT803X_PHY_MMD3_WOL_CTRL 0x8012
#define AT803X_WOL_EN BIT(5)
#define AT803X_REG_CHIP_CONFIG 0x1f
#define AT803X_BT_BX_REG_SEL 0x8000
@ -866,30 +863,6 @@ static int at8031_config_init(struct phy_device *phydev)
return at803x_config_init(phydev);
}
static int at8031_set_wol(struct phy_device *phydev,
struct ethtool_wolinfo *wol)
{
int ret;
/* First setup MAC address and enable WOL interrupt */
ret = at803x_set_wol(phydev, wol);
if (ret)
return ret;
if (wol->wolopts & WAKE_MAGIC)
/* Enable WOL function for 1588 */
ret = phy_modify_mmd(phydev, MDIO_MMD_PCS,
AT803X_PHY_MMD3_WOL_CTRL,
0, AT803X_WOL_EN);
else
/* Disable WoL function for 1588 */
ret = phy_modify_mmd(phydev, MDIO_MMD_PCS,
AT803X_PHY_MMD3_WOL_CTRL,
AT803X_WOL_EN, 0);
return ret;
}
static int at8031_config_intr(struct phy_device *phydev)
{
struct at803x_priv *priv = phydev->priv;

View File

@ -633,7 +633,7 @@ static struct phy_driver qca808x_driver[] = {
.handle_interrupt = at803x_handle_interrupt,
.get_tunable = at803x_get_tunable,
.set_tunable = at803x_set_tunable,
.set_wol = at803x_set_wol,
.set_wol = at8031_set_wol,
.get_wol = at803x_get_wol,
.get_features = qca808x_get_features,
.config_aneg = qca808x_config_aneg,

View File

@ -115,6 +115,31 @@ int at803x_set_wol(struct phy_device *phydev,
}
EXPORT_SYMBOL_GPL(at803x_set_wol);
int at8031_set_wol(struct phy_device *phydev,
struct ethtool_wolinfo *wol)
{
int ret;
/* First setup MAC address and enable WOL interrupt */
ret = at803x_set_wol(phydev, wol);
if (ret)
return ret;
if (wol->wolopts & WAKE_MAGIC)
/* Enable WOL function for 1588 */
ret = phy_modify_mmd(phydev, MDIO_MMD_PCS,
AT803X_PHY_MMD3_WOL_CTRL,
0, AT803X_WOL_EN);
else
/* Disable WoL function for 1588 */
ret = phy_modify_mmd(phydev, MDIO_MMD_PCS,
AT803X_PHY_MMD3_WOL_CTRL,
AT803X_WOL_EN, 0);
return ret;
}
EXPORT_SYMBOL_GPL(at8031_set_wol);
void at803x_get_wol(struct phy_device *phydev,
struct ethtool_wolinfo *wol)
{

View File

@ -172,6 +172,9 @@
#define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B
#define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A
#define AT803X_PHY_MMD3_WOL_CTRL 0x8012
#define AT803X_WOL_EN BIT(5)
#define AT803X_DEBUG_ADDR 0x1D
#define AT803X_DEBUG_DATA 0x1E
@ -215,6 +218,8 @@ int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg,
int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data);
int at803x_set_wol(struct phy_device *phydev,
struct ethtool_wolinfo *wol);
int at8031_set_wol(struct phy_device *phydev,
struct ethtool_wolinfo *wol);
void at803x_get_wol(struct phy_device *phydev,
struct ethtool_wolinfo *wol);
int at803x_ack_interrupt(struct phy_device *phydev);

View File

@ -155,10 +155,29 @@ static int smsc_phy_reset(struct phy_device *phydev)
static int lan87xx_config_aneg(struct phy_device *phydev)
{
int rc;
u8 mdix_ctrl;
int val;
int rc;
switch (phydev->mdix_ctrl) {
/* When auto-negotiation is disabled (forced mode), the PHY's
* Auto-MDIX will continue toggling the TX/RX pairs.
*
* To establish a stable link, we must select a fixed MDI mode.
* If the user has not specified a fixed MDI mode (i.e., mdix_ctrl is
* 'auto'), we default to ETH_TP_MDI. This choice of a ETH_TP_MDI mode
* mirrors the behavior the hardware would exhibit if the AUTOMDIX_EN
* strap were configured for a fixed MDI connection.
*/
if (phydev->autoneg == AUTONEG_DISABLE) {
if (phydev->mdix_ctrl == ETH_TP_MDI_AUTO)
mdix_ctrl = ETH_TP_MDI;
else
mdix_ctrl = phydev->mdix_ctrl;
} else {
mdix_ctrl = phydev->mdix_ctrl;
}
switch (mdix_ctrl) {
case ETH_TP_MDI:
val = SPECIAL_CTRL_STS_OVRRD_AMDIX_;
break;
@ -167,7 +186,8 @@ static int lan87xx_config_aneg(struct phy_device *phydev)
SPECIAL_CTRL_STS_AMDIX_STATE_;
break;
case ETH_TP_MDI_AUTO:
val = SPECIAL_CTRL_STS_AMDIX_ENABLE_;
val = SPECIAL_CTRL_STS_OVRRD_AMDIX_ |
SPECIAL_CTRL_STS_AMDIX_ENABLE_;
break;
default:
return genphy_config_aneg(phydev);
@ -183,7 +203,7 @@ static int lan87xx_config_aneg(struct phy_device *phydev)
rc |= val;
phy_write(phydev, SPECIAL_CTRL_STS, rc);
phydev->mdix = phydev->mdix_ctrl;
phydev->mdix = mdix_ctrl;
return genphy_config_aneg(phydev);
}
@ -261,6 +281,33 @@ int lan87xx_read_status(struct phy_device *phydev)
}
EXPORT_SYMBOL_GPL(lan87xx_read_status);
static int lan87xx_phy_config_init(struct phy_device *phydev)
{
int rc;
/* The LAN87xx PHY's initial MDI-X mode is determined by the AUTOMDIX_EN
* hardware strap, but the driver cannot read the strap's status. This
* creates an unpredictable initial state.
*
* To ensure consistent and reliable behavior across all boards,
* override the strap configuration on initialization and force the PHY
* into a known state with Auto-MDIX enabled, which is the expected
* default for modern hardware.
*/
rc = phy_modify(phydev, SPECIAL_CTRL_STS,
SPECIAL_CTRL_STS_OVRRD_AMDIX_ |
SPECIAL_CTRL_STS_AMDIX_ENABLE_ |
SPECIAL_CTRL_STS_AMDIX_STATE_,
SPECIAL_CTRL_STS_OVRRD_AMDIX_ |
SPECIAL_CTRL_STS_AMDIX_ENABLE_);
if (rc < 0)
return rc;
phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
return smsc_phy_config_init(phydev);
}
static int lan874x_phy_config_init(struct phy_device *phydev)
{
u16 val;
@ -695,7 +742,7 @@ static struct phy_driver smsc_phy_driver[] = {
/* basic functions */
.read_status = lan87xx_read_status,
.config_init = smsc_phy_config_init,
.config_init = lan87xx_phy_config_init,
.soft_reset = smsc_phy_reset,
.config_aneg = lan87xx_config_aneg,

View File

@ -243,8 +243,8 @@ int __vsock_dgram_recvmsg(struct socket *sock, struct msghdr *msg,
int vsock_dgram_recvmsg(struct socket *sock, struct msghdr *msg,
size_t len, int flags);
#ifdef CONFIG_BPF_SYSCALL
extern struct proto vsock_proto;
#ifdef CONFIG_BPF_SYSCALL
int vsock_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool restore);
void __init vsock_bpf_build_proto(void);
#else

View File

@ -1350,8 +1350,7 @@ hci_conn_hash_lookup_big_state(struct hci_dev *hdev, __u8 handle, __u16 state)
rcu_read_lock();
list_for_each_entry_rcu(c, &h->list, list) {
if (c->type != BIS_LINK || bacmp(&c->dst, BDADDR_ANY) ||
c->state != state)
if (c->type != BIS_LINK || c->state != state)
continue;
if (handle == c->iso_qos.bcast.big) {

View File

@ -114,7 +114,6 @@ struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r,
struct netlink_ext_ack *extack);
void qdisc_put_rtab(struct qdisc_rate_table *tab);
void qdisc_put_stab(struct qdisc_size_table *tab);
void qdisc_warn_nonwc(const char *txt, struct Qdisc *qdisc);
bool sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
struct net_device *dev, struct netdev_queue *txq,
spinlock_t *root_lock, bool validate);
@ -290,4 +289,28 @@ static inline bool tc_qdisc_stats_dump(struct Qdisc *sch,
return true;
}
static inline void qdisc_warn_nonwc(const char *txt, struct Qdisc *qdisc)
{
if (!(qdisc->flags & TCQ_F_WARN_NONWC)) {
pr_warn("%s: %s qdisc %X: is non-work-conserving?\n",
txt, qdisc->ops->id, qdisc->handle >> 16);
qdisc->flags |= TCQ_F_WARN_NONWC;
}
}
static inline unsigned int qdisc_peek_len(struct Qdisc *sch)
{
struct sk_buff *skb;
unsigned int len;
skb = sch->ops->peek(sch);
if (unlikely(skb == NULL)) {
qdisc_warn_nonwc("qdisc_peek_len", sch);
return 0;
}
len = qdisc_pkt_len(skb);
return len;
}
#endif

View File

@ -45,7 +45,8 @@
#include <net/atmclip.h>
static struct net_device *clip_devs;
static struct atm_vcc *atmarpd;
static struct atm_vcc __rcu *atmarpd;
static DEFINE_MUTEX(atmarpd_lock);
static struct timer_list idle_timer;
static const struct neigh_ops clip_neigh_ops;
@ -53,24 +54,35 @@ static int to_atmarpd(enum atmarp_ctrl_type type, int itf, __be32 ip)
{
struct sock *sk;
struct atmarp_ctrl *ctrl;
struct atm_vcc *vcc;
struct sk_buff *skb;
int err = 0;
pr_debug("(%d)\n", type);
if (!atmarpd)
return -EUNATCH;
rcu_read_lock();
vcc = rcu_dereference(atmarpd);
if (!vcc) {
err = -EUNATCH;
goto unlock;
}
skb = alloc_skb(sizeof(struct atmarp_ctrl), GFP_ATOMIC);
if (!skb)
return -ENOMEM;
if (!skb) {
err = -ENOMEM;
goto unlock;
}
ctrl = skb_put(skb, sizeof(struct atmarp_ctrl));
ctrl->type = type;
ctrl->itf_num = itf;
ctrl->ip = ip;
atm_force_charge(atmarpd, skb->truesize);
atm_force_charge(vcc, skb->truesize);
sk = sk_atm(atmarpd);
sk = sk_atm(vcc);
skb_queue_tail(&sk->sk_receive_queue, skb);
sk->sk_data_ready(sk);
return 0;
unlock:
rcu_read_unlock();
return err;
}
static void link_vcc(struct clip_vcc *clip_vcc, struct atmarp_entry *entry)
@ -417,6 +429,8 @@ static int clip_mkip(struct atm_vcc *vcc, int timeout)
if (!vcc->push)
return -EBADFD;
if (vcc->user_back)
return -EINVAL;
clip_vcc = kmalloc(sizeof(struct clip_vcc), GFP_KERNEL);
if (!clip_vcc)
return -ENOMEM;
@ -607,17 +621,27 @@ static void atmarpd_close(struct atm_vcc *vcc)
{
pr_debug("\n");
rtnl_lock();
atmarpd = NULL;
mutex_lock(&atmarpd_lock);
RCU_INIT_POINTER(atmarpd, NULL);
mutex_unlock(&atmarpd_lock);
synchronize_rcu();
skb_queue_purge(&sk_atm(vcc)->sk_receive_queue);
rtnl_unlock();
pr_debug("(done)\n");
module_put(THIS_MODULE);
}
static int atmarpd_send(struct atm_vcc *vcc, struct sk_buff *skb)
{
atm_return_tx(vcc, skb);
dev_kfree_skb_any(skb);
return 0;
}
static const struct atmdev_ops atmarpd_dev_ops = {
.close = atmarpd_close
.close = atmarpd_close,
.send = atmarpd_send
};
@ -631,15 +655,18 @@ static struct atm_dev atmarpd_dev = {
static int atm_init_atmarp(struct atm_vcc *vcc)
{
rtnl_lock();
if (vcc->push == clip_push)
return -EINVAL;
mutex_lock(&atmarpd_lock);
if (atmarpd) {
rtnl_unlock();
mutex_unlock(&atmarpd_lock);
return -EADDRINUSE;
}
mod_timer(&idle_timer, jiffies + CLIP_CHECK_INTERVAL * HZ);
atmarpd = vcc;
rcu_assign_pointer(atmarpd, vcc);
set_bit(ATM_VF_META, &vcc->flags);
set_bit(ATM_VF_READY, &vcc->flags);
/* allow replies and avoid getting closed if signaling dies */
@ -648,13 +675,14 @@ static int atm_init_atmarp(struct atm_vcc *vcc)
vcc->push = NULL;
vcc->pop = NULL; /* crash */
vcc->push_oam = NULL; /* crash */
rtnl_unlock();
mutex_unlock(&atmarpd_lock);
return 0;
}
static int clip_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
struct atm_vcc *vcc = ATM_SD(sock);
struct sock *sk = sock->sk;
int err = 0;
switch (cmd) {
@ -675,14 +703,18 @@ static int clip_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
err = clip_create(arg);
break;
case ATMARPD_CTRL:
lock_sock(sk);
err = atm_init_atmarp(vcc);
if (!err) {
sock->state = SS_CONNECTED;
__module_get(THIS_MODULE);
}
release_sock(sk);
break;
case ATMARP_MKIP:
lock_sock(sk);
err = clip_mkip(vcc, arg);
release_sock(sk);
break;
case ATMARP_SETENTRY:
err = clip_setentry(vcc, (__force __be32)arg);

View File

@ -6966,7 +6966,10 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
bis->iso_qos.bcast.in.sdu = le16_to_cpu(ev->max_pdu);
if (!ev->status) {
bis->state = BT_CONNECTED;
set_bit(HCI_CONN_BIG_SYNC, &bis->flags);
hci_debugfs_create_conn(bis);
hci_conn_add_sysfs(bis);
hci_iso_setup_path(bis);
}
}

View File

@ -1345,7 +1345,7 @@ int hci_setup_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance)
* Command Disallowed error, so we must first disable the
* instance if it is active.
*/
if (adv && !adv->pending) {
if (adv) {
err = hci_disable_ext_adv_instance_sync(hdev, instance);
if (err)
return err;
@ -5493,7 +5493,7 @@ static int hci_disconnect_sync(struct hci_dev *hdev, struct hci_conn *conn,
{
struct hci_cp_disconnect cp;
if (test_bit(HCI_CONN_BIG_CREATED, &conn->flags)) {
if (conn->type == BIS_LINK) {
/* This is a BIS connection, hci_conn_del will
* do the necessary cleanup.
*/

View File

@ -1176,7 +1176,7 @@ restart:
goto do_error;
while (msg_data_left(msg)) {
ssize_t copy = 0;
int copy = 0;
skb = tcp_write_queue_tail(sk);
if (skb)

View File

@ -5181,7 +5181,9 @@ end:
skb_condense(skb);
skb_set_owner_r(skb, sk);
}
tcp_rcvbuf_grow(sk);
/* do not grow rcvbuf for not-yet-accepted or orphaned sockets. */
if (sk->sk_socket)
tcp_rcvbuf_grow(sk);
}
static int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb,

View File

@ -387,7 +387,6 @@ static void netlink_skb_set_owner_r(struct sk_buff *skb, struct sock *sk)
WARN_ON(skb->sk != NULL);
skb->sk = sk;
skb->destructor = netlink_skb_destructor;
atomic_add(skb->truesize, &sk->sk_rmem_alloc);
sk_mem_charge(sk, skb->truesize);
}
@ -1212,41 +1211,48 @@ struct sk_buff *netlink_alloc_large_skb(unsigned int size, int broadcast)
int netlink_attachskb(struct sock *sk, struct sk_buff *skb,
long *timeo, struct sock *ssk)
{
DECLARE_WAITQUEUE(wait, current);
struct netlink_sock *nlk;
unsigned int rmem;
nlk = nlk_sk(sk);
rmem = atomic_add_return(skb->truesize, &sk->sk_rmem_alloc);
if ((atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf ||
test_bit(NETLINK_S_CONGESTED, &nlk->state))) {
DECLARE_WAITQUEUE(wait, current);
if (!*timeo) {
if (!ssk || netlink_is_kernel(ssk))
netlink_overrun(sk);
sock_put(sk);
kfree_skb(skb);
return -EAGAIN;
}
__set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&nlk->wait, &wait);
if ((atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf ||
test_bit(NETLINK_S_CONGESTED, &nlk->state)) &&
!sock_flag(sk, SOCK_DEAD))
*timeo = schedule_timeout(*timeo);
__set_current_state(TASK_RUNNING);
remove_wait_queue(&nlk->wait, &wait);
sock_put(sk);
if (signal_pending(current)) {
kfree_skb(skb);
return sock_intr_errno(*timeo);
}
return 1;
if ((rmem == skb->truesize || rmem < READ_ONCE(sk->sk_rcvbuf)) &&
!test_bit(NETLINK_S_CONGESTED, &nlk->state)) {
netlink_skb_set_owner_r(skb, sk);
return 0;
}
netlink_skb_set_owner_r(skb, sk);
return 0;
atomic_sub(skb->truesize, &sk->sk_rmem_alloc);
if (!*timeo) {
if (!ssk || netlink_is_kernel(ssk))
netlink_overrun(sk);
sock_put(sk);
kfree_skb(skb);
return -EAGAIN;
}
__set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&nlk->wait, &wait);
rmem = atomic_read(&sk->sk_rmem_alloc);
if (((rmem && rmem + skb->truesize > READ_ONCE(sk->sk_rcvbuf)) ||
test_bit(NETLINK_S_CONGESTED, &nlk->state)) &&
!sock_flag(sk, SOCK_DEAD))
*timeo = schedule_timeout(*timeo);
__set_current_state(TASK_RUNNING);
remove_wait_queue(&nlk->wait, &wait);
sock_put(sk);
if (signal_pending(current)) {
kfree_skb(skb);
return sock_intr_errno(*timeo);
}
return 1;
}
static int __netlink_sendskb(struct sock *sk, struct sk_buff *skb)
@ -1307,6 +1313,7 @@ static int netlink_unicast_kernel(struct sock *sk, struct sk_buff *skb,
ret = -ECONNREFUSED;
if (nlk->netlink_rcv != NULL) {
ret = skb->len;
atomic_add(skb->truesize, &sk->sk_rmem_alloc);
netlink_skb_set_owner_r(skb, sk);
NETLINK_CB(skb).sk = ssk;
netlink_deliver_tap_kernel(sk, ssk, skb);
@ -1383,13 +1390,19 @@ EXPORT_SYMBOL_GPL(netlink_strict_get_check);
static int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb)
{
struct netlink_sock *nlk = nlk_sk(sk);
unsigned int rmem, rcvbuf;
if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf &&
rmem = atomic_add_return(skb->truesize, &sk->sk_rmem_alloc);
rcvbuf = READ_ONCE(sk->sk_rcvbuf);
if ((rmem != skb->truesize || rmem <= rcvbuf) &&
!test_bit(NETLINK_S_CONGESTED, &nlk->state)) {
netlink_skb_set_owner_r(skb, sk);
__netlink_sendskb(sk, skb);
return atomic_read(&sk->sk_rmem_alloc) > (sk->sk_rcvbuf >> 1);
return rmem > (rcvbuf >> 1);
}
atomic_sub(skb->truesize, &sk->sk_rmem_alloc);
return -1;
}
@ -2249,6 +2262,7 @@ static int netlink_dump(struct sock *sk, bool lock_taken)
struct module *module;
int err = -ENOBUFS;
int alloc_min_size;
unsigned int rmem;
int alloc_size;
if (!lock_taken)
@ -2258,9 +2272,6 @@ static int netlink_dump(struct sock *sk, bool lock_taken)
goto errout_skb;
}
if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf)
goto errout_skb;
/* NLMSG_GOODSIZE is small to avoid high order allocations being
* required, but it makes sense to _attempt_ a 32KiB allocation
* to reduce number of system calls on dump operations, if user
@ -2283,6 +2294,12 @@ static int netlink_dump(struct sock *sk, bool lock_taken)
if (!skb)
goto errout_skb;
rmem = atomic_add_return(skb->truesize, &sk->sk_rmem_alloc);
if (rmem >= READ_ONCE(sk->sk_rcvbuf)) {
atomic_sub(skb->truesize, &sk->sk_rmem_alloc);
goto errout_skb;
}
/* Trim skb to allocated size. User is expected to provide buffer as
* large as max(min_dump_alloc, 32KiB (max_recvmsg_len capped at
* netlink_recvmsg())). dump will pack as many smaller messages as

View File

@ -361,12 +361,15 @@ struct rxrpc_local {
struct list_head new_client_calls; /* Newly created client calls need connection */
spinlock_t client_call_lock; /* Lock for ->new_client_calls */
struct sockaddr_rxrpc srx; /* local address */
/* Provide a kvec table sufficiently large to manage either a DATA
* packet with a maximum set of jumbo subpackets or a PING ACK padded
* out to 64K with zeropages for PMTUD.
*/
struct kvec kvec[1 + RXRPC_MAX_NR_JUMBO > 3 + 16 ?
1 + RXRPC_MAX_NR_JUMBO : 3 + 16];
union {
/* Provide a kvec table sufficiently large to manage either a
* DATA packet with a maximum set of jumbo subpackets or a PING
* ACK padded out to 64K with zeropages for PMTUD.
*/
struct kvec kvec[1 + RXRPC_MAX_NR_JUMBO > 3 + 16 ?
1 + RXRPC_MAX_NR_JUMBO : 3 + 16];
struct bio_vec bvec[3 + 16];
};
};
/*

View File

@ -149,6 +149,7 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx,
id_in_use:
write_unlock(&rx->call_lock);
rxrpc_prefail_call(call, RXRPC_CALL_LOCAL_ERROR, -EBADSLT);
rxrpc_cleanup_call(call);
_leave(" = -EBADSLT");
return -EBADSLT;
@ -254,6 +255,9 @@ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx,
unsigned short call_tail, conn_tail, peer_tail;
unsigned short call_count, conn_count;
if (!b)
return NULL;
/* #calls >= #conns >= #peers must hold true. */
call_head = smp_load_acquire(&b->call_backlog_head);
call_tail = b->call_backlog_tail;

View File

@ -924,7 +924,7 @@ void rxrpc_send_response(struct rxrpc_connection *conn, struct sk_buff *response
{
struct rxrpc_skb_priv *sp = rxrpc_skb(response);
struct scatterlist sg[16];
struct bio_vec bvec[16];
struct bio_vec *bvec = conn->local->bvec;
struct msghdr msg;
size_t len = sp->resp.len;
__be32 wserial;
@ -938,6 +938,9 @@ void rxrpc_send_response(struct rxrpc_connection *conn, struct sk_buff *response
if (ret < 0)
goto fail;
nr_sg = ret;
ret = -EIO;
if (WARN_ON_ONCE(nr_sg > ARRAY_SIZE(conn->local->bvec)))
goto fail;
for (int i = 0; i < nr_sg; i++)
bvec_set_page(&bvec[i], sg_page(&sg[i]), sg[i].length, sg[i].offset);

View File

@ -336,17 +336,22 @@ out:
return q;
}
static struct Qdisc *qdisc_leaf(struct Qdisc *p, u32 classid)
static struct Qdisc *qdisc_leaf(struct Qdisc *p, u32 classid,
struct netlink_ext_ack *extack)
{
unsigned long cl;
const struct Qdisc_class_ops *cops = p->ops->cl_ops;
if (cops == NULL)
return NULL;
if (cops == NULL) {
NL_SET_ERR_MSG(extack, "Parent qdisc is not classful");
return ERR_PTR(-EOPNOTSUPP);
}
cl = cops->find(p, classid);
if (cl == 0)
return NULL;
if (cl == 0) {
NL_SET_ERR_MSG(extack, "Specified class not found");
return ERR_PTR(-ENOENT);
}
return cops->leaf(p, cl);
}
@ -596,16 +601,6 @@ out:
qdisc_skb_cb(skb)->pkt_len = pkt_len;
}
void qdisc_warn_nonwc(const char *txt, struct Qdisc *qdisc)
{
if (!(qdisc->flags & TCQ_F_WARN_NONWC)) {
pr_warn("%s: %s qdisc %X: is non-work-conserving?\n",
txt, qdisc->ops->id, qdisc->handle >> 16);
qdisc->flags |= TCQ_F_WARN_NONWC;
}
}
EXPORT_SYMBOL(qdisc_warn_nonwc);
static enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer)
{
struct qdisc_watchdog *wd = container_of(timer, struct qdisc_watchdog,
@ -1490,7 +1485,7 @@ static int __tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n,
NL_SET_ERR_MSG(extack, "Failed to find qdisc with specified classid");
return -ENOENT;
}
q = qdisc_leaf(p, clid);
q = qdisc_leaf(p, clid, extack);
} else if (dev_ingress_queue(dev)) {
q = rtnl_dereference(dev_ingress_queue(dev)->qdisc_sleeping);
}
@ -1501,6 +1496,8 @@ static int __tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n,
NL_SET_ERR_MSG(extack, "Cannot find specified qdisc on specified device");
return -ENOENT;
}
if (IS_ERR(q))
return PTR_ERR(q);
if (tcm->tcm_handle && q->handle != tcm->tcm_handle) {
NL_SET_ERR_MSG(extack, "Invalid handle");
@ -1602,7 +1599,9 @@ static int __tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n,
NL_SET_ERR_MSG(extack, "Failed to find specified qdisc");
return -ENOENT;
}
q = qdisc_leaf(p, clid);
q = qdisc_leaf(p, clid, extack);
if (IS_ERR(q))
return PTR_ERR(q);
} else if (dev_ingress_queue_create(dev)) {
q = rtnl_dereference(dev_ingress_queue(dev)->qdisc_sleeping);
}

View File

@ -835,22 +835,6 @@ update_vf(struct hfsc_class *cl, unsigned int len, u64 cur_time)
}
}
static unsigned int
qdisc_peek_len(struct Qdisc *sch)
{
struct sk_buff *skb;
unsigned int len;
skb = sch->ops->peek(sch);
if (unlikely(skb == NULL)) {
qdisc_warn_nonwc("qdisc_peek_len", sch);
return 0;
}
len = qdisc_pkt_len(skb);
return len;
}
static void
hfsc_adjust_levels(struct hfsc_class *cl)
{

View File

@ -989,7 +989,7 @@ static struct sk_buff *agg_dequeue(struct qfq_aggregate *agg,
if (cl->qdisc->q.qlen == 0) /* no more packets, remove from list */
list_del_init(&cl->alist);
else if (cl->deficit < qdisc_pkt_len(cl->qdisc->ops->peek(cl->qdisc))) {
else if (cl->deficit < qdisc_peek_len(cl->qdisc)) {
cl->deficit += agg->lmax;
list_move_tail(&cl->alist, &agg->active);
}

View File

@ -704,8 +704,10 @@ static void tipc_topsrv_stop(struct net *net)
for (id = 0; srv->idr_in_use; id++) {
con = idr_find(&srv->conn_idr, id);
if (con) {
conn_get(con);
spin_unlock_bh(&srv->idr_lock);
tipc_conn_close(con);
conn_put(con);
spin_lock_bh(&srv->idr_lock);
}
}

View File

@ -407,6 +407,8 @@ EXPORT_SYMBOL_GPL(vsock_enqueue_accept);
static bool vsock_use_local_transport(unsigned int remote_cid)
{
lockdep_assert_held(&vsock_register_mutex);
if (!transport_local)
return false;
@ -464,6 +466,8 @@ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk)
remote_flags = vsk->remote_addr.svm_flags;
mutex_lock(&vsock_register_mutex);
switch (sk->sk_type) {
case SOCK_DGRAM:
new_transport = transport_dgram;
@ -479,12 +483,15 @@ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk)
new_transport = transport_h2g;
break;
default:
return -ESOCKTNOSUPPORT;
ret = -ESOCKTNOSUPPORT;
goto err;
}
if (vsk->transport) {
if (vsk->transport == new_transport)
return 0;
if (vsk->transport == new_transport) {
ret = 0;
goto err;
}
/* transport->release() must be called with sock lock acquired.
* This path can only be taken during vsock_connect(), where we
@ -508,8 +515,16 @@ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk)
/* We increase the module refcnt to prevent the transport unloading
* while there are open sockets assigned to it.
*/
if (!new_transport || !try_module_get(new_transport->module))
return -ENODEV;
if (!new_transport || !try_module_get(new_transport->module)) {
ret = -ENODEV;
goto err;
}
/* It's safe to release the mutex after a successful try_module_get().
* Whichever transport `new_transport` points at, it won't go away until
* the last module_put() below or in vsock_deassign_transport().
*/
mutex_unlock(&vsock_register_mutex);
if (sk->sk_type == SOCK_SEQPACKET) {
if (!new_transport->seqpacket_allow ||
@ -528,12 +543,31 @@ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk)
vsk->transport = new_transport;
return 0;
err:
mutex_unlock(&vsock_register_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(vsock_assign_transport);
/*
* Provide safe access to static transport_{h2g,g2h,dgram,local} callbacks.
* Otherwise we may race with module removal. Do not use on `vsk->transport`.
*/
static u32 vsock_registered_transport_cid(const struct vsock_transport **transport)
{
u32 cid = VMADDR_CID_ANY;
mutex_lock(&vsock_register_mutex);
if (*transport)
cid = (*transport)->get_local_cid();
mutex_unlock(&vsock_register_mutex);
return cid;
}
bool vsock_find_cid(unsigned int cid)
{
if (transport_g2h && cid == transport_g2h->get_local_cid())
if (cid == vsock_registered_transport_cid(&transport_g2h))
return true;
if (transport_h2g && cid == VMADDR_CID_HOST)
@ -2536,18 +2570,19 @@ static long vsock_dev_do_ioctl(struct file *filp,
unsigned int cmd, void __user *ptr)
{
u32 __user *p = ptr;
u32 cid = VMADDR_CID_ANY;
int retval = 0;
u32 cid;
switch (cmd) {
case IOCTL_VM_SOCKETS_GET_LOCAL_CID:
/* To be compatible with the VMCI behavior, we prioritize the
* guest CID instead of well-know host CID (VMADDR_CID_HOST).
*/
if (transport_g2h)
cid = transport_g2h->get_local_cid();
else if (transport_h2g)
cid = transport_h2g->get_local_cid();
cid = vsock_registered_transport_cid(&transport_g2h);
if (cid == VMADDR_CID_ANY)
cid = vsock_registered_transport_cid(&transport_h2g);
if (cid == VMADDR_CID_ANY)
cid = vsock_registered_transport_cid(&transport_local);
if (put_user(cid, p) != 0)
retval = -EFAULT;

View File

@ -0,0 +1,53 @@
// SPDX-License-Identifier: GPL-2.0
--mss=1000
`./defaults.sh
sysctl -q net.ipv4.tcp_rmem="4096 131072 $((32*1024*1024))"`
// Test that a not-yet-accepted socket does not change
// its initial sk_rcvbuf (tcp_rmem[1]) when receiving ooo packets.
+0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+0 bind(3, ..., ...) = 0
+0 listen(3, 1) = 0
+0 < S 0:0(0) win 65535 <mss 1000,nop,nop,sackOK,nop,wscale 7>
+0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 10>
+.1 < . 1:1(0) ack 1 win 257
+0 < . 2001:41001(39000) ack 1 win 257
+0 > . 1:1(0) ack 1 <nop,nop,sack 2001:41001>
+0 < . 41001:101001(60000) ack 1 win 257
+0 > . 1:1(0) ack 1 <nop,nop,sack 2001:101001>
+0 < . 1:1001(1000) ack 1 win 257
+0 > . 1:1(0) ack 1001 <nop,nop,sack 2001:101001>
+0 < . 1001:2001(1000) ack 1 win 257
+0 > . 1:1(0) ack 101001
+0 accept(3, ..., ...) = 4
+0 %{ assert SK_MEMINFO_RCVBUF == 131072, SK_MEMINFO_RCVBUF }%
+0 close(4) = 0
+0 close(3) = 0
// Test that ooo packets for accepted sockets do increase sk_rcvbuf
+0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+0 bind(3, ..., ...) = 0
+0 listen(3, 1) = 0
+0 < S 0:0(0) win 65535 <mss 1000,nop,nop,sackOK,nop,wscale 7>
+0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 10>
+.1 < . 1:1(0) ack 1 win 257
+0 accept(3, ..., ...) = 4
+0 < . 2001:41001(39000) ack 1 win 257
+0 > . 1:1(0) ack 1 <nop,nop,sack 2001:41001>
+0 < . 41001:101001(60000) ack 1 win 257
+0 > . 1:1(0) ack 1 <nop,nop,sack 2001:101001>
+0 %{ assert SK_MEMINFO_RCVBUF > 131072, SK_MEMINFO_RCVBUF }%

View File

@ -635,5 +635,42 @@
"$TC qdisc del dev $DUMMY handle 1:0 root",
"$IP addr del 10.10.10.10/24 dev $DUMMY || true"
]
},
{
"id": "d74b",
"name": "Test use-after-free with DRR/NETEM/BLACKHOLE chain",
"category": [
"qdisc",
"hfsc",
"drr",
"netem",
"blackhole"
],
"plugins": {
"requires": [
"nsPlugin",
"scapyPlugin"
]
},
"setup": [
"$IP link set dev $DUMMY up || true",
"$IP addr add 10.10.11.10/24 dev $DUMMY || true",
"$TC qdisc add dev $DUMMY root handle 1: drr",
"$TC filter add dev $DUMMY parent 1: basic classid 1:1",
"$TC class add dev $DUMMY parent 1: classid 1:1 drr",
"$TC qdisc add dev $DUMMY parent 1:1 handle 2: hfsc def 1",
"$TC class add dev $DUMMY parent 2: classid 2:1 hfsc rt m1 8 d 1 m2 0",
"$TC qdisc add dev $DUMMY parent 2:1 handle 3: netem",
"$TC qdisc add dev $DUMMY parent 3:1 handle 4: blackhole",
"ping -c1 -W0.01 -I $DUMMY 10.10.11.11 || true",
"$TC class del dev $DUMMY classid 1:1"
],
"cmdUnderTest": "ping -c1 -W0.01 -I $DUMMY 10.10.11.11",
"expExitCode": "1",
"verifyCmd": "$TC -j class ls dev $DUMMY classid 1:1",
"matchJSON": [],
"teardown": [
"$TC qdisc del dev $DUMMY root handle 1: drr"
]
}
]