/*
 * DF-3641 — bnx_sysctl_std_refill() updates bnx_rx_ret_ring[] using
 * bnx_tx_ringcnt as the loop bound (copy-paste bug)
 *
 * Trigger (HARDWARE REQUIRED for the sysctl node to exist; the loop-bound
 * bug itself is source-provable and was verified on the guest's
 * byte-identical /usr/src copy):
 *
 *   sys/dev/netif/bnx/if_bnx.c:
 *     5664:  bnx_sysctl_std_refill(SYSCTL_HANDLER_ARGS)
 *     5667:      struct bnx_rx_ret_ring *ret = &sc->bnx_rx_ret_ring[0];
 *     5679:      if ((cntmax * sc->bnx_rx_retcnt) >= BGE_STD_RX_RING_CNT/2)
 *                        -> EINVAL
 *     5684:      for (i = 0; i < sc->bnx_tx_ringcnt; ++i)      <-- WRONG
 *     5685:          sc->bnx_rx_ret_ring[i].bnx_rx_cntmax = cntmax;
 *
 *   The loop should run over sc->bnx_rx_retcnt (the RX return-ring count);
 *   it runs over bnx_tx_ringcnt.  On BCM5719/5720 with rx_retcnt > 1 and
 *   tx_ringcnt == 1 (the common non-bundled RSS setup, e.g. hw.bnx.tx_rings
 *   unset on a 4-RX/1-TX configuration), writing
 *   dev.bnx.0.std_refill=<n> updates ONLY ring 0; rings 1..rx_retcnt-1 keep
 *   the default bnx_rx_cntmax set in bnx_dma_alloc()
 *   (if_bnx.c:4259-4260: (BGE_STD_RX_RING_CNT / 4) / sc->bnx_rx_retcnt),
 *   so the operator-visible "std_refill" value silently disagrees with the
 *   per-ring scheduling thresholds actually in force.
 *
 *   Not memory-unsafe: tx_ringcnt <= rx_retcnt is structurally guaranteed
 *   (bnx_setup_ring_cnt() if_bnx.c:5784-5799 clamps TX ring_max to
 *   min(BNX_TX_RING_MAX, rx_retcnt) and if_ringcnt_fixup() clamps the
 *   count, sys/net/if.c:3944-3953), so the loop can never run past the
 *   bnx_rx_ret_ring[] allocation; the KASSERT at if_bnx.c:5797 documents
 *   the invariant.  Also, the validation at 5679 admits negative cntmax
 *   ((n*retcnt) is negative, never >= 256), which then truncates into the
 *   uint16_t bnx_rx_cntmax (if_bnxvar.h:204) — e.g. -5 becomes 65531,
 *   which makes `bnx_rx_cnt >= bnx_rx_cntmax' (if_bnx.c:2825) almost
 *   never fire: refill scheduling from that path stops (RX eventually
 *   still refills via the bnx_rx_std_used >= 256 check at if_bnx.c:2890).
 *   Root-only sysctl; performance/correctness only.
 *
 *   The audit QEMU guest has no Broadcom NIC, so dev.bnx.0.std_refill does
 *   not exist there (run.log: sysctl hw.bnx unknown oid).
 */
#include <sys/types.h>
#include <sys/sysctl.h>
#include <stdio.h>

int
main(void)
{
	size_t len;
	int v;

	len = sizeof(v);
	if (sysctlbyname("dev.bnx.0.std_refill", &v, &len, NULL, 0) < 0) {
		fprintf(stderr, "DF-3641: dev.bnx.0.std_refill absent "
		    "(no bnx hardware) — as expected on the audit guest.\n");
		return 1;
	}
	/* On hardware with rx_retcnt > tx_ringcnt this write only reaches
	 * rings [0, tx_ringcnt); read back `dev.bnx.0.rx_rings`,
	 * `dev.bnx.0.tx_rings`, and per-ring behavior to observe the
	 * mismatch. */
	fprintf(stderr, "std_refill=%d — compare rx_rings/tx_rings counts; "
	    "rings [%d..%d) keep the old cntmax\n", v, 1, v);
	return 0;
}
